Compare commits
1052 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 760f119cf1 | |||
| 035dc70f77 | |||
| b892aebfe8 | |||
| 156ad8a318 | |||
| 74433f1ca8 | |||
| 7042fdacbc | |||
| 5ec1b18115 | |||
| abfa6d4644 | |||
| 730c1e6bc4 | |||
| e1366c9a6f | |||
| 9d9b3a110d | |||
| 92893feef2 | |||
| 775c64f21c | |||
| dbd131cc88 | |||
| 7e295782c3 | |||
| f2b1fa1399 | |||
| 4ca86478ee | |||
| eb53372646 | |||
| 111d6ae5cf | |||
| cc2b556e65 | |||
| 69acda60ec | |||
| efe07e28c1 | |||
| fe2a4862ad | |||
| 7503cd841a | |||
| 8b099099d9 | |||
| b6c7afbb26 | |||
| 0997df9069 | |||
| 91f9205adb | |||
| e62bcae84b | |||
| 8ff6083faf | |||
| 648fecab61 | |||
| db1ea288ef | |||
| 8a3922ad30 | |||
| d4b9dcfb15 | |||
| 4b678ffee8 | |||
| 3ae81a0835 | |||
| 4fe7f6bc86 | |||
| ffa4d6a829 | |||
| 0d51bb3f73 | |||
| 8bac0d5de1 | |||
| e2166f086d | |||
| 8f4a9974b1 | |||
| e93f8920c1 | |||
| 0021a7fb65 | |||
| eec1e84e72 | |||
| fddf50db2a | |||
| 8cf8e32bb4 | |||
| f4bbf91a08 | |||
| 0b558a470e | |||
| 816adb335a | |||
| a67e67d42e | |||
| 9f5b4b2fd3 | |||
| a32a87c346 | |||
| 7be76e40f4 | |||
| 0a7aae6aaf | |||
| 6a893d200c | |||
| e651c58384 | |||
| 0636feb5aa | |||
| 276bcfd0bb | |||
| 3d09ba536c | |||
| a454664a1d | |||
| b9ca7b686b | |||
| 763969f965 | |||
| df617bee5e | |||
| 159de7fd68 | |||
| cc369a2b40 | |||
| d8d4d924ad | |||
| 1330d64b22 | |||
| e404b252b1 | |||
| af6dd20503 | |||
| 7e61c2e40d | |||
| 265af52853 | |||
| bea98d0749 | |||
| ff9186f1dc | |||
| 871fce1661 | |||
| 5657dec7af | |||
| 0f23104156 | |||
| e23a588bad | |||
| c44e921e0b | |||
| 8d09f734cd | |||
| ef281ab8c6 | |||
| aa082ca119 | |||
| fc3f23976b | |||
| 2fe41b81c5 | |||
| 0f4a3567b1 | |||
| 9f90e76a0c | |||
| 3220eb4c1b | |||
| f01bed49d5 | |||
| 5777d37af1 | |||
| 833ffa3aab | |||
| d0487f5869 | |||
| a2308e8518 | |||
| 07662e65ba | |||
| bc834aa083 | |||
| 46f5d5470a | |||
| 69d754cb77 | |||
| e8b403e0b9 | |||
| 83dcaf932f | |||
| 15a6f4b1b3 | |||
| d19fa4a8f1 | |||
| 869adbbd1c | |||
| 9e3bbcb5e1 | |||
| e72606ffb6 | |||
| 425daf97b4 | |||
| 709d0b30fe | |||
| 4cede79c69 | |||
| 32782cc69f | |||
| c5ea85a212 | |||
| e62f0787f8 | |||
| 88c18714c9 | |||
| 7c61da51cf | |||
| c93b9a2125 | |||
| 6b75f9c486 | |||
| d9b4647e11 | |||
| 078d815ad5 | |||
| 7c4a229fbc | |||
| e8faa6254e | |||
| 3c5dc9d3a7 | |||
| 0f6480a303 | |||
| 073720049b | |||
| efde1c17f1 | |||
| 964b509df0 | |||
| 39fc5b4fff | |||
| e37e273375 | |||
| 4cd37cce64 | |||
| f0e54bbe9f | |||
| 754cbccf56 | |||
| ffd1b627e2 | |||
| efd070e7b2 | |||
| 83f4ba6069 | |||
| 7a704400ab | |||
| 2c549825ea | |||
| 87dc452498 | |||
| 1261bad465 | |||
| 0d3ef08d6f | |||
| bc22983319 | |||
| 014e1b0e76 | |||
| 77039ebf7e | |||
| f386f9db4b | |||
| 1822632ce6 | |||
| b4bcfd8fa5 | |||
| 2e2fb13389 | |||
| 6704e26553 | |||
| 3d67023c9c | |||
| 229225cab5 | |||
| b253509c8b | |||
| c22eb26949 | |||
| 827ad77989 | |||
| ed49bcd543 | |||
| fe23ebfec1 | |||
| 143a8da8d6 | |||
| 085afb9549 | |||
| 07428a1def | |||
| 29ed1a27b9 | |||
| 7ac0d4826c | |||
| 583096e059 | |||
| 477577696f | |||
| a97f8c9bdf | |||
| d2e23d3886 | |||
| ea986d3260 | |||
| 7c6375761d | |||
| 02e4e5a6a0 | |||
| fec7951493 | |||
| 6980b00031 | |||
| c6c2716726 | |||
| 9089d1ec95 | |||
| e4e631725a | |||
| bcb2886e5b | |||
| 6c0a78e1c7 | |||
| d554c13cc8 | |||
| dc6b07abe3 | |||
| 8c0f7bb032 | |||
| ac0d8e922b | |||
| d9fa202bbb | |||
| a65bd14fa1 | |||
| e0dd25a5e0 | |||
| 312fbc4f8d | |||
| b6be4d9a4d | |||
| 7a9abb3f6f | |||
| b5dbb9c705 | |||
| 7e014ba67b | |||
| 3bd50b83d4 | |||
| 7fa12b8806 | |||
| aa01b789be | |||
| 09baf89e70 | |||
| 3483751d9d | |||
| e0c027edf4 | |||
| 97e33e1df0 | |||
| 1f4130e15e | |||
| 8a001e66b1 | |||
| ce2e896fcb | |||
| ef4d5b3cd6 | |||
| c1a9cb6de6 | |||
| bf50e0da6f | |||
| 362b112a77 | |||
| 6b424ca736 | |||
| 4560115ec8 | |||
| c89bab7e42 | |||
| bbac29011e | |||
| c60c6b67ab | |||
| 8767a6eb4e | |||
| 539b772d6b | |||
| bc6c8131b5 | |||
| 632145f3a5 | |||
| feb6252fae | |||
| 5f3fb1b548 | |||
| c92736d124 | |||
| 3f07514a44 | |||
| 9b3288dc18 | |||
| 1d6be38cc8 | |||
| 4a42f07ad2 | |||
| 072cca75ce | |||
| f4f78af7dd | |||
| 6341547de6 | |||
| 8282937409 | |||
| 8361bb299b | |||
| 2109acacd5 | |||
| 7a8e77b24a | |||
| 751fe08d98 | |||
| 33195758f0 | |||
| 30bde95314 | |||
| aaf13dc3c2 | |||
| e0e8ca9f67 | |||
| 8ac0b91f78 | |||
| 05466aa85a | |||
| 5be88bfe57 | |||
| 17295fdcde | |||
| 7821217b60 | |||
| 68485f8bbf | |||
| f0cd188d73 | |||
| 5a94a87d67 | |||
| fab3a48efe | |||
| 1e75a20a49 | |||
| 2205d11bf5 | |||
| 583c737c15 | |||
| 8649f7f9e9 | |||
| 0c48a4e68d | |||
| fda51675fc | |||
| 4c586edefa | |||
| 11a5cf4a06 | |||
| b3bbfccef4 | |||
| b8d201e18a | |||
| 15829d25a9 | |||
| 44a6abe0b7 | |||
| c6393f1f23 | |||
| 83ed0e8820 | |||
| 049b5490ba | |||
| 35d339e137 | |||
| a218bee02d | |||
| 59c0d35a32 | |||
| 794867863f | |||
| 2c5e6f8a4e | |||
| 23a732a107 | |||
| 370727c2fb | |||
| ea70a64733 | |||
| 7d596c7216 | |||
| b26e3736c1 | |||
| a86ee04ce6 | |||
| 7750a08f65 | |||
| a22d921c17 | |||
| 010d9b89d0 | |||
| c82cd6704b | |||
| 55011709b0 | |||
| bcc68b091b | |||
| e6fcf60b8e | |||
| 68f38ef5a4 | |||
| 9ee9311122 | |||
| 6f2a153a44 | |||
| 3502d10db3 | |||
| b38865e056 | |||
| b659709f2f | |||
| add9a1e9ad | |||
| 447c8387a2 | |||
| f7f519dcc4 | |||
| 39ba239618 | |||
| e9b59a540e | |||
| c92563577c | |||
| d1f0dc6376 | |||
| 9753e7301e | |||
| 884a7ac5c1 | |||
| e589831baa | |||
| 1a44d9343c | |||
| 631fd3b08d | |||
| 3bd81ca3be | |||
| b94d2687f8 | |||
| 86751fa022 | |||
| 71e1acd1b0 | |||
| c00379c85c | |||
| 5d628bf703 | |||
| 66835ab703 | |||
| 4aeccc7b5b | |||
| bc38aa4173 | |||
| 7f283d3a61 | |||
| 504c307197 | |||
| f9604d9ebb | |||
| 34c4d37ff0 | |||
| d171f5b873 | |||
| 5a583f4918 | |||
| ad0880f33b | |||
| 9c544f4701 | |||
| 6b249254da | |||
| 55296dc01b | |||
| 3334c52558 | |||
| 257743a26d | |||
| 2f83bbaa50 | |||
| e63632f872 | |||
| 6033af8dd1 | |||
| 656d9522e0 | |||
| 107a83d634 | |||
| 43d8adc717 | |||
| 02c31c9246 | |||
| 0810b54837 | |||
| 9e9f7c0b44 | |||
| 686220b3ae | |||
| e54741d1f9 | |||
| 39c59ba0cd | |||
| 49c7baaa44 | |||
| 9585a65341 | |||
| 81ceb534f3 | |||
| 383e49921c | |||
| fb484d9530 | |||
| 479d7175f6 | |||
| f28afb3069 | |||
| ec48677623 | |||
| 71e3d4dc6d | |||
| 6eaa5b44cf | |||
| 69cdead4fc | |||
| fb3b6fd699 | |||
| 4aba37bd3b | |||
| 6557cd5523 | |||
| ac8ae6b0ee | |||
| ec8d7d9c1e | |||
| 8959c489f2 | |||
| b4d939bd38 | |||
| f26b0e7671 | |||
| b6441120c5 | |||
| e5acd7847f | |||
| f30492c37f | |||
| c03be40bb5 | |||
| 5dd62e7a08 | |||
| 439d09333d | |||
| 4352fab581 | |||
| 4c8dc87a28 | |||
| c42d235336 | |||
| d54fa25512 | |||
| 7d118628a4 | |||
| 3a2d6530a3 | |||
| 0ad45c90fa | |||
| 1c88fb4cda | |||
| 2b33da2a33 | |||
| daf0420aa4 | |||
| 8c2a400be2 | |||
| 582d23c884 | |||
| 6ef9c61220 | |||
| 5fe009246f | |||
| b101b5646f | |||
| 279e529dab | |||
| f93e26d6a5 | |||
| a642059809 | |||
| 3fbd7f61b6 | |||
| bb5b6307df | |||
| 6cb8956275 | |||
| 89b1d058fb | |||
| b4ef4c2dc8 | |||
| 1dbd1651ad | |||
| efef8c4895 | |||
| cdd6e1d724 | |||
| ed945f347e | |||
| 1c9ba78db0 | |||
| dbb755833a | |||
| 8f8f6bb5e1 | |||
| 3a8564acb1 | |||
| 0cb66802c6 | |||
| f6632ff53b | |||
| 0420946391 | |||
| e4915514bd | |||
| 8bdf5c3608 | |||
| 1f84dd7159 | |||
| c00aaa29a4 | |||
| 0c8b93e28a | |||
| 5e6d4245db | |||
| 2b48347ec3 | |||
| 765adc1690 | |||
| 3cad66317f | |||
| f3d9d2381b | |||
| 036d402f34 | |||
| 891a05dfdb | |||
| 3f3fa5aa31 | |||
| 22693772a6 | |||
| 715747a054 | |||
| cc71c8b504 | |||
| ee7ad8fcb7 | |||
| b7edddf553 | |||
| ab0d910edc | |||
| 1250493b2f | |||
| d729869093 | |||
| f99bf07949 | |||
| a9611d8e7f | |||
| b284ec81a5 | |||
| 5e91f0a07d | |||
| 88d253f383 | |||
| c2112cbe40 | |||
| d81fc37201 | |||
| 3cff405f9e | |||
| 62ffca0dfd | |||
| 5b24a10e54 | |||
| 40eb20a970 | |||
| 7d055b7a28 | |||
| 145f9dff8f | |||
| 5250470d17 | |||
| a2c9029e3f | |||
| d477a7178f | |||
| 842c43d557 | |||
| 1bbdd25a22 | |||
| 1f39d25523 | |||
| 764280843c | |||
| caa3fa7f9f | |||
| b24c133f60 | |||
| ee878fc161 | |||
| 3b005f03fe | |||
| 796a8bc2b3 | |||
| f790e06bc3 | |||
| 6c93c24107 | |||
| ac65b549ac | |||
| f3bb32f284 | |||
| 3deda6cab6 | |||
| 866ccbe818 | |||
| 3442a5c475 | |||
| 704feb689c | |||
| dcc9b447cb | |||
| 56b797b0bb | |||
| 1e628422a3 | |||
| 26563d7f30 | |||
| 6cc874356c | |||
| 4aae7a0129 | |||
| 6701f53be9 | |||
| 4a7932a15e | |||
| 95e62bec1f | |||
| e10aca5304 | |||
| 2aec524970 | |||
| 9eaf3d8b71 | |||
| 9dcc6a79fa | |||
| e39db348e5 | |||
| 1def28243d | |||
| c675cda187 | |||
| f535d0e8dd | |||
| 2ebc6b71c9 | |||
| 0ca065b7c2 | |||
| 4944af825e | |||
| 7c44272788 | |||
| 3dc0bd320a | |||
| fe5c2bcdc2 | |||
| 3f0a28fe18 | |||
| b0885e18a1 | |||
| ab4f43d818 | |||
| 00b572dfdf | |||
| 0f5b7340dd | |||
| d224010908 | |||
| f412cb04d7 | |||
| dc7240348e | |||
| 9efcd841b9 | |||
| 641fd77b4e | |||
| e89b790394 | |||
| 90eed8c8ef | |||
| 4a83f39eb5 | |||
| 4369f2be15 | |||
| 43242c8672 | |||
| ab475d3ed7 | |||
| c0d68d79cc | |||
| 15f134a85a | |||
| 3fab712c1e | |||
| 518f5407fa | |||
| 7f10a5a590 | |||
| 058d0730dd | |||
| 4e92b11f09 | |||
| af77e4c2e4 | |||
| e3460fa423 | |||
| 771b5010e7 | |||
| ab39638013 | |||
| 0b95b4b080 | |||
| b8fb0338e1 | |||
| 3f917ab018 | |||
| dd51aedc2f | |||
| 6616fca614 | |||
| 2e3f36a958 | |||
| dd1f8458b4 | |||
| 9d9b5da489 | |||
| cecc9022fa | |||
| ce11b31f3b | |||
| d2c84c9d4c | |||
| 88b883191b | |||
| 8129295567 | |||
| d2c7d51d00 | |||
| b05ee61a96 | |||
| 148eaf9c80 | |||
| 03c71fa649 | |||
| 3414173a17 | |||
| a4b9a51304 | |||
| 27d6979ea5 | |||
| 97c9723c8f | |||
| 212fa3171c | |||
| e295cb5837 | |||
| 9d9d80c124 | |||
| f1abfa5fde | |||
| ef9c8bf522 | |||
| 893683b559 | |||
| 2b95216443 | |||
| e661113bbd | |||
| cda85a59ac | |||
| 566a276495 | |||
| 31fc221295 | |||
| e70c75b60c | |||
| 0a705f29e4 | |||
| f76ec3d91c | |||
| 22ec52bf2c | |||
| 30031f7d7b | |||
| 2959f467ce | |||
| 190a1de6f7 | |||
| 59cd4c1aff | |||
| bf3b49d23b | |||
| 10f5bdffe2 | |||
| b23edef723 | |||
| 06dd4c14e4 | |||
| ef55b435e5 | |||
| af3dd14fe0 | |||
| 4de27cdee1 | |||
| f32d372a9a | |||
| 4346c1d6ad | |||
| 7f0109069b | |||
| b0b00d426c | |||
| 38a1faf55d | |||
| c08d333386 | |||
| 7bcb155f6a | |||
| 904b727ac0 | |||
| 7910ae1578 | |||
| 96fa9f7471 | |||
| b4c27dac05 | |||
| b7e70987ff | |||
| c22e0f8ec8 | |||
| 0f9ec68b45 | |||
| 2e8e30099e | |||
| 2258424a33 | |||
| 0794fd91bd | |||
| 55b724ed82 | |||
| df2b544093 | |||
| 2309f23a21 | |||
| 14b3afe238 | |||
| c733edf13c | |||
| 47039fc7d4 | |||
| c25ce452cb | |||
| b135fb8a59 | |||
| 7ca1ca6a5c | |||
| 31eba923af | |||
| d48bfb5671 | |||
| fa638dd3d6 | |||
| d2c52297ae | |||
| 1c49c133ea | |||
| 52221a939c | |||
| 2fd91c95fc | |||
| 35be8465ea | |||
| 8d5e233acf | |||
| 662c5c5248 | |||
| bf8d2862f8 | |||
| 40e93383ae | |||
| 93791cc2a2 | |||
| e19725fcbe | |||
| 9d12e06dbc | |||
| 4994130a96 | |||
| 03b7305ca1 | |||
| 54ec59e5ee | |||
| ce8db94ed2 | |||
| bf34dfb00a | |||
| f1bb031e43 | |||
| 58ba4559eb | |||
| e033c5a564 | |||
| aa72ffdfa5 | |||
| 9405db0ad6 | |||
| 3f18bb3a7f | |||
| 191165a280 | |||
| 2ec5b2e02e | |||
| f4fb14342c | |||
| 6e9102ff56 | |||
| a6fdb2785e | |||
| 2900984662 | |||
| 48e269b777 | |||
| 7462d17cd2 | |||
| 8c24b03a8d | |||
| 493f3c3ee1 | |||
| 77dfaa7c15 | |||
| 1c6ef2dda5 | |||
| cd98711e9d | |||
| 394c19d408 | |||
| 1711b3f569 | |||
| afa73a0f10 | |||
| 72b53f53de | |||
| f9f1f82374 | |||
| 0f7e5403eb | |||
| cafc238073 | |||
| 185a0cd1a0 | |||
| 46c1fd7e8d | |||
| f1224c3d75 | |||
| 2e7646b11d | |||
| ca5d04c7da | |||
| 79a8a5a4e5 | |||
| 20aeea43ae | |||
| 22245583b4 | |||
| cbcc50c80d | |||
| 11cfd9eac0 | |||
| d746320dd3 | |||
| 4afedce20d | |||
| 79c921a4c1 | |||
| 2226408acc | |||
| 4f552247b1 | |||
| a26e424787 | |||
| 5be8ca11a1 | |||
| 150bd6d922 | |||
| a41909d0c5 | |||
| 593ab19a0f | |||
| ef8f8086d5 | |||
| 17dbe2ac54 | |||
| 595ca70a29 | |||
| 300269fa36 | |||
| f4d7f82bf7 | |||
| 893e347c8e | |||
| ce779a6f6e | |||
| 0b9bb00cf4 | |||
| ec11088c91 | |||
| 92f8e13d53 | |||
| 907e9a0f30 | |||
| e621b60110 | |||
| 5a92cfc1a0 | |||
| 519c874a5b | |||
| 76dc052e15 | |||
| 68eabdf497 | |||
| 0e0c1b467a | |||
| eb3d502914 | |||
| 1e586b007f | |||
| 4e593327cd | |||
| 0dac8e59cd | |||
| 70019eaa8f | |||
| 82c8123cac | |||
| ae186119be | |||
| 6de62ee5a4 | |||
| e91961e2f2 | |||
| b87bdfb146 | |||
| e657930a55 | |||
| 8bef3e3651 | |||
| 29468988d5 | |||
| 4c876760ca | |||
| a1c2e5e24d | |||
| f62d8d956d | |||
| 0dd1c396a1 | |||
| 24b25c7891 | |||
| d0d2b9239f | |||
| d5815d8d53 | |||
| c7db1b7cbb | |||
| 64759ce1a3 | |||
| 054266a4b3 | |||
| b3b4deba3b | |||
| 7ff67b1a39 | |||
| 3a88a04e47 | |||
| 02d4539cae | |||
| 45da727c67 | |||
| baa8144439 | |||
| adff5b4649 | |||
| 3482f716a3 | |||
| 6d1b6d0d02 | |||
| 2e10aa4cfd | |||
| b495a035c4 | |||
| 5b652198fe | |||
| e40657de17 | |||
| 1ede920d60 | |||
| bc2fdf77ff | |||
| 35e579b61b | |||
| 96c2ea8956 | |||
| a94f92b4f9 | |||
| 86e4ccb246 | |||
| e38f75e512 | |||
| 56dc323e71 | |||
| 17683c89ff | |||
| f83d069814 | |||
| 160d3cc825 | |||
| 8fd4d28990 | |||
| 220c7ad69b | |||
| 03d3125c20 | |||
| 02b78d07f4 | |||
| ceb7831e50 | |||
| 2f3323ba68 | |||
| 39c4b5ac92 | |||
| e42b607790 | |||
| a58f12fe95 | |||
| 4790ac0a20 | |||
| 6a2f3acb88 | |||
| 89ee433676 | |||
| 70cbad1d25 | |||
| f8c0aa0241 | |||
| 5edad1303c | |||
| 58b9c4ec45 | |||
| 7de34e33a8 | |||
| 199bdd9dd9 | |||
| 4bbb6eb6ae | |||
| cdde5f7f12 | |||
| c9a93eb735 | |||
| 65f4b83103 | |||
| 959274c3fc | |||
| bf4d034f1d | |||
| 04f68be19e | |||
| 9cf1ebd754 | |||
| 38ada90269 | |||
| be40e97a97 | |||
| 2b9e9f4302 | |||
| 5181bf0714 | |||
| 2950cbfeab | |||
| 95feb85cb8 | |||
| 6466abe35e | |||
| f015f9e660 | |||
| 161fb6f4d1 | |||
| e636e5e9b4 | |||
| 0db794c553 | |||
| 9f92c57e69 | |||
| 7aa16adef0 | |||
| 5690ae9183 | |||
| 76f5a7d73e | |||
| 5bb008fe60 | |||
| 8b4d799f25 | |||
| f380cc1031 | |||
| 787d6f6ee7 | |||
| 7d31b635ea | |||
| 1583fd17e7 | |||
| d63f3cf0f4 | |||
| 184da3fa5c | |||
| 9e4822e54e | |||
| 36df9267d0 | |||
| 37ee313287 | |||
| 3c0d5a6a78 | |||
| b0853ccdf3 | |||
| 51480d4573 | |||
| 5e4e06dbc3 | |||
| 3b183c64ee | |||
| ee0e8358f2 | |||
| ebef5188d0 | |||
| 044a4394ad | |||
| a0452b1439 | |||
| e9c9ab26f1 | |||
| 5da9968af3 | |||
| 6f162dda04 | |||
| 16f6912f37 | |||
| e27faa696e | |||
| d929386a18 | |||
| 36ddf7491f | |||
| 0fec5d8152 | |||
| fbbf35456f | |||
| 82d552ac56 | |||
| 1938bdf841 | |||
| b07aceb7a4 | |||
| f61057f208 | |||
| f4e9588993 | |||
| 47e8783e7e | |||
| 520f852a21 | |||
| a814bcd513 | |||
| 0d30c1390d | |||
| 6b6c1beded | |||
| 992c2d3508 | |||
| 3c0d3f8709 | |||
| c61cbbf296 | |||
| 1d519b89d7 | |||
| bf4c35eee5 | |||
| 0f372a0a73 | |||
| 5db9b2ac4c | |||
| 189927b46f | |||
| 65955e2fb1 | |||
| eabc37ce41 | |||
| 9e72341e34 | |||
| 4393b58dce | |||
| 102af04076 | |||
| 7a7fafda99 | |||
| 12cbf387ca | |||
| c3fb682f73 | |||
| de68d8faea | |||
| 64e497aba9 | |||
| f8f8c93509 | |||
| 1996a78b43 | |||
| e4d58452f4 | |||
| 984b0a83de | |||
| c93738bd53 | |||
| dc7d03e49d | |||
| 0aa72a7eba | |||
| 0dd8232afe | |||
| 9a469f0216 | |||
| 8f236daf09 | |||
| 17ccb0bc75 | |||
| ca7fca068a | |||
| e3079f0476 | |||
| 9aa72c4482 | |||
| 74d2bc3b8b | |||
| 82d69fd301 | |||
| 536cfa24b0 | |||
| 20158a6906 | |||
| 5f0efafcaa | |||
| 260acc1b51 | |||
| bc7bb8bf96 | |||
| 17d10f6889 | |||
| 888d89126b | |||
| 16fb116cf0 | |||
| 6c66ae2ee4 | |||
| 511d9fa7ba | |||
| 78d8bca4d3 | |||
| bf517ce489 | |||
| 70118fee99 | |||
| 66359f61ec | |||
| 453dccc462 | |||
| 632693ff4a | |||
| 1bd639f31d | |||
| 7b9a92f719 | |||
| 459f6845b1 | |||
| 0ca5e834c0 | |||
| 63c06b0c58 | |||
| 0576062396 | |||
| f2c7e4b929 | |||
| 3caf4a3e5c | |||
| 75a62205e9 | |||
| 54dc44b7a2 | |||
| 5a2cb18a48 | |||
| 8ee6ce76e4 | |||
| 17e6dc8298 | |||
| df8580f2f0 | |||
| ea50637d16 | |||
| ad4871d86c | |||
| ad831b8f26 | |||
| d87f781615 | |||
| 3514f6ff69 | |||
| 03116894b3 | |||
| ef69c49622 | |||
| b86d5523dd | |||
| ba6c9512a3 | |||
| c4f55aa749 | |||
| 97fd5e03b4 | |||
| 30007c5703 | |||
| a27099b057 | |||
| f1b7652904 | |||
| db20cb8390 | |||
| ed9d42f033 | |||
| 8573385d4c | |||
| 9d80842cc3 | |||
| 623df76820 | |||
| 3d7addb8fc | |||
| 23358eeb17 | |||
| cd32655cd2 | |||
| b2b196182c | |||
| 95b5b968a6 | |||
| 546688dac4 | |||
| 99997cd292 | |||
| c2f87e9170 | |||
| 94788ae5ea | |||
| d6ddbcd278 | |||
| 7f12aaf402 | |||
| 6b8f86f1de | |||
| b40f9b9685 | |||
| 1e6e5cf82e | |||
| 961aac86a3 | |||
| e1b218a38a | |||
| 503b916ab7 | |||
| 4e34a25806 | |||
| a7e8bf34bc | |||
| 6645a9fa93 | |||
| 9364605355 | |||
| ff63cfd072 | |||
| e6517681d6 | |||
| d8f7b14d80 | |||
| 631fc5df2f | |||
| 2154ca5dea | |||
| a5e931f672 | |||
| be94fa2215 | |||
| ce72be82fb | |||
| 4549caa570 | |||
| 1da2217ce8 | |||
| 8a42776d3f | |||
| 01f34021dc | |||
| 5da7f5bd60 | |||
| 4f62f8e999 | |||
| 11d669e34b | |||
| a388002a57 | |||
| f5ca411fa7 | |||
| 1ce167f82d | |||
| 06446ddb68 | |||
| f9eb5d95a5 | |||
| b13a40744d | |||
| fe1ff6476c | |||
| 417ce97d05 | |||
| aa79acfab2 | |||
| 4d0aaf97de | |||
| 5e72f7eb77 | |||
| e822ae7acb | |||
| 702823499e | |||
| c382ff1308 | |||
| 1ede8085f5 | |||
| 8863b25212 | |||
| 2f36af5003 | |||
| 710d5de922 | |||
| 062b07565e | |||
| f052b4c10f | |||
| a5d2e20fbc | |||
| d3de894568 | |||
| 52f93c6183 | |||
| 137c29497d | |||
| 0193114231 | |||
| 69e130c704 | |||
| e7a6a9a375 | |||
| 63cd495e98 | |||
| e4da6b3499 | |||
| d1a2a0f134 | |||
| b1fae5fe50 | |||
| 40f823846d | |||
| 0e61e0bbc0 | |||
| 8d2a20ab9b | |||
| 0d6b2761a2 | |||
| bdd8f81329 | |||
| 7fc477ed20 | |||
| 4a39d1de00 | |||
| fcb51fbe6d | |||
| 113127583a | |||
| 9e380e00a9 | |||
| 0448e95fef | |||
| c0e7d2e45d | |||
| 837669d1ac | |||
| c117abf0ab | |||
| f439d173c2 | |||
| af8332e66d | |||
| 87fa95250b | |||
| 9042e01fb9 | |||
| ef96ff8f47 | |||
| 00131be336 | |||
| 826e19618f | |||
| 8c9430638e | |||
| fdd56cacb3 | |||
| 19aa28b499 | |||
| d6a40056d2 | |||
| 0e307e3de2 | |||
| 1a01a1e7bb | |||
| c9f328930d | |||
| c8b6306344 | |||
| 548a980006 | |||
| 18b587baeb | |||
| 12fa229b4a | |||
| a018d0a18d | |||
| 2a1712d0f3 | |||
| bbc911baca | |||
| 305d2ef620 | |||
| b7e6ffd8d3 | |||
| 5b141f6a20 | |||
| 32b225ca7f | |||
| b2999beaf8 | |||
| 6f72963535 | |||
| 02c5be558e | |||
| b410b609eb | |||
| 0ecbd128e3 | |||
| 95a5527ae9 | |||
| c2797f37cd | |||
| 009a1bea38 | |||
| de56bc6444 | |||
| 547b6890b9 | |||
| c0d57013e1 | |||
| 55a07214fe | |||
| bb7ee95a7b | |||
| d20a8350a1 | |||
| 60dc1b5f7a | |||
| 4d4f454424 | |||
| 2269ded856 | |||
| 8432c6614b | |||
| 6f2c6fa6d1 | |||
| 0a3da31bf9 | |||
| 054dab12c8 | |||
| bf9a61a3c2 | |||
| c5f3a44d55 | |||
| c344d3b25a | |||
| cb5ab38b09 | |||
| cc2a6e1158 | |||
| 000b805803 | |||
| 5e8049b8dc | |||
| db5ec5cf33 | |||
| 182b14b8ec | |||
| 7f1bc9ed1e | |||
| 6d6a64bbbe | |||
| cd64c6838e | |||
| 8dfa279755 | |||
| 63f134ecf5 | |||
| 62363d8021 | |||
| 3911115764 | |||
| a31ed06b10 | |||
| 84450e8a9d | |||
| 6fd48d0a3a | |||
| 52011e5c44 | |||
| a9fba6b110 | |||
| 404da76e17 | |||
| cb8931646f | |||
| f160c496ff | |||
| f747f0983b | |||
| 5217af8068 | |||
| 9cd0d1ab64 | |||
| bb66e542a3 | |||
| 0740ab86e6 | |||
| 30ffa34849 | |||
| c01e7d1ed8 | |||
| b53758f5a5 | |||
| a765060351 | |||
| 7542155399 | |||
| a79f657a9f | |||
| 5cdc2e5f50 | |||
| 9f9633ce6f | |||
| 2ffa5631f5 | |||
| 29907e0bf0 | |||
| 3259f338d1 | |||
| 3433056f50 | |||
| 7dd1fab9d4 | |||
| 8eabd4605b | |||
| aeebda1fcf | |||
| 05025ab263 | |||
| 447d3b8988 | |||
| b8d14c9f54 | |||
| 02547255ff | |||
| e6c832339c | |||
| 1a20af2405 | |||
| f09c8ab9f2 | |||
| e5d8f5af5c | |||
| 6865a4ccfe | |||
| f54d2c7df5 | |||
| 3351872cbe | |||
| 16848183dd | |||
| f299f00c87 | |||
| abc6b7b793 | |||
| ec3c8b5326 | |||
| 5d614aa865 | |||
| 28f8c710df | |||
| 736f2fa165 | |||
| 4585d058c8 | |||
| 129a56046f | |||
| df0e83c8f7 | |||
| e2ebfcd1e9 | |||
| 05fc7efd60 | |||
| 480bba15df | |||
| 42597cc6c5 | |||
| 023104e407 | |||
| 9c73205ecc | |||
| 39fd1a04b6 | |||
| 3a86950eb0 | |||
| 825eebf51d | |||
| afc8bd66cc | |||
| 6af7ac92b6 | |||
| cdd8150e00 | |||
| 73ef0e730c | |||
| c1e7f3a462 | |||
| bdeb91b5d7 |
+1
-1
@@ -1 +1 @@
|
||||
* @actions/virtual-environments-owners
|
||||
* @actions/runner-images-team
|
||||
|
||||
@@ -28,17 +28,21 @@ body:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Virtual environments affected
|
||||
label: Platforms affected
|
||||
options:
|
||||
- label: Azure DevOps
|
||||
- label: GitHub Actions
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Runner images affected
|
||||
options:
|
||||
- label: Ubuntu 18.04
|
||||
- label: Ubuntu 20.04
|
||||
- label: macOS 10.15
|
||||
- label: Ubuntu 22.04
|
||||
- label: macOS 11
|
||||
- label: Windows Server 2016
|
||||
- label: macOS 12
|
||||
- label: macOS 13
|
||||
- label: Windows Server 2019
|
||||
- label: Windows Server 2022
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Mitigation ways
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: Submit a bug report
|
||||
labels: [needs triage]
|
||||
description: Submit a bug report.
|
||||
labels: [bug report, needs triage]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
@@ -10,25 +10,30 @@ body:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Virtual environments affected
|
||||
label: Platforms affected
|
||||
options:
|
||||
- label: Azure DevOps
|
||||
- label: GitHub Actions - Standard Runners
|
||||
- label: GitHub Actions - Larger Runners
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Runner images affected
|
||||
options:
|
||||
- label: Ubuntu 18.04
|
||||
- label: Ubuntu 20.04
|
||||
- label: macOS 10.15
|
||||
- label: Ubuntu 22.04
|
||||
- label: macOS 11
|
||||
- label: Windows Server 2016
|
||||
- label: macOS 12
|
||||
- label: macOS 13
|
||||
- label: Windows Server 2019
|
||||
- label: Windows Server 2022
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Image version and build link
|
||||
description: |
|
||||
Image version where you are experiencing the issue. Where to find image version in build logs:
|
||||
1. For GitHub Actions, under "Set up job" -> "Virtual Environment" -> "Version".
|
||||
2. For Azure DevOps, under "Initialize job" -> "Virtual Environment" -> "Version".
|
||||
|
||||
1. For GitHub Actions, under "Set up job" -> "Runner Image" -> "Version".
|
||||
2. For Azure DevOps, under "Initialize job" -> "Runner Image" -> "Version".
|
||||
|
||||
If you have a public example, please, provide a link to the failed build.
|
||||
validations:
|
||||
required: true
|
||||
@@ -36,14 +41,20 @@ body:
|
||||
attributes:
|
||||
label: Is it regression?
|
||||
description: If yes, please, provide the latest image version where the issue didn't persist, and a link to the latest successful build.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: A description of what is actually happening.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Repro steps
|
||||
@@ -51,5 +62,5 @@ body:
|
||||
A description with steps to reproduce the issue.
|
||||
1. Step 1
|
||||
2. Step 2
|
||||
validations:
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: Get help in GitHub Discussions
|
||||
url: https://github.com/actions/runner-images/discussions
|
||||
about: Have a question? Feel free to ask in the runner-images GitHub Discussions!
|
||||
|
||||
@@ -44,22 +44,26 @@ body:
|
||||
label: URL for tool's homepage
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Provide a basic test case to validate the tool's functionality.
|
||||
label: Provide a basic test case to validate the tool's functionality.
|
||||
description: This will be automatically formatted into code.
|
||||
render: bash
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Virtual environments affected
|
||||
label: Platforms where you need the tool
|
||||
options:
|
||||
- label: Azure DevOps
|
||||
- label: GitHub Actions
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Runner images where you need the tool
|
||||
options:
|
||||
- label: Ubuntu 18.04
|
||||
- label: Ubuntu 20.04
|
||||
- label: macOS 10.15
|
||||
- label: Ubuntu 22.04
|
||||
- label: macOS 11
|
||||
- label: Windows Server 2016
|
||||
- label: macOS 12
|
||||
- label: macOS 13
|
||||
- label: Windows Server 2019
|
||||
- label: Windows Server 2022
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Can this tool be installed during the build?
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Description
|
||||
New tool, Bug fixing, or Improvement?
|
||||
Please include a summary of the change and which issue is fixed. Also include relevant motivation and context.
|
||||
New tool, Bug fixing, or Improvement?
|
||||
Please include a summary of the change and which issue is fixed. Also include relevant motivation and context.
|
||||
**For new tools, please provide total size and installation time.**
|
||||
|
||||
<!-- Currently, we can't accept external contributions to macOS source. Please find more details in [CONTRIBUTING.md](CONTRIBUTING.md#macOS) guide -->
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '32 4 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python', 'ruby' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Create release for ${{ github.event.client_payload.ReleaseBranchName }}
|
||||
uses: actions/create-release@v1.1.1
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -45,5 +45,5 @@ jobs:
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: ${{ steps.create-pr.outputs.result }},
|
||||
team_reviewers: ['virtual-environments-akvelon']
|
||||
})
|
||||
team_reviewers: ['runner-images-team']
|
||||
})
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
name: Create and upload a SBOM to release assets
|
||||
# Inherited variables:
|
||||
# github.event.client_payload.agentSpec - Current YAML Label
|
||||
# github.event.client_payload.ReleaseID - Current release ID
|
||||
# github.event.client_payload.imageVersion - AzDO image version "major.minor"
|
||||
# github.event.client_payload.ReleaseBranchName - Necessary to identify workflow run
|
||||
#
|
||||
# Current SYFT tool issues:
|
||||
# macOS (minor): very long cataloging process (more than 6 hours) (https://github.com/anchore/syft/issues/1328),
|
||||
# macOS (major): prompt privilegies that blocking process indefinetely (https://github.com/anchore/syft/issues/1367)
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [generate-sbom]
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
jobs:
|
||||
#Checking image version on available runner
|
||||
version-check:
|
||||
runs-on: ${{ github.event.client_payload.agentSpec }}
|
||||
steps:
|
||||
- name: Available image version check for ${{ github.event.client_payload.ReleaseBranchName }}
|
||||
run: |
|
||||
if ($env:ImageVersion -ne '${{ github.event.client_payload.imageVersion }}') {
|
||||
throw "Current runner $env:ImageVersion image version don't match ${{ github.event.client_payload.imageVersion }}."
|
||||
}
|
||||
#Install and run SYFT, compress SBOM, upload it to release assets
|
||||
create-sbom:
|
||||
needs: version-check
|
||||
runs-on: ${{ github.event.client_payload.agentSpec }}
|
||||
steps:
|
||||
#Installation section
|
||||
- name: Install SYFT tool on Windows
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
run: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b D:/syft
|
||||
- name: Install SYFT tool on Ubuntu or macOS
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
#Running section.
|
||||
- name: Run SYFT on Windows
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
run: D:/syft/syft dir:C:/ -vv -o spdx-json=sbom.json
|
||||
- name: Run SYFT on Ubuntu
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: syft dir:/ -vv -o spdx-json=sbom.json
|
||||
- name: Run SYFT on macOS
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
run: syft dir:/ -vv -o spdx-json=sbom.json --exclude ./Users --exclude ./System/Volumes --exclude ./private
|
||||
shell: bash
|
||||
#Preparing artifact (raw SBOM.json is too big)
|
||||
- name: Compress SBOM file
|
||||
run: Compress-Archive sbom.json sbom.json.zip
|
||||
#Upload artifact action
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sbom-${{ github.event.client_payload.agentSpec }}-${{ github.event.client_payload.imageVersion }}
|
||||
path: sbom.json.zip
|
||||
if-no-files-found: warn
|
||||
#Upload release asset action
|
||||
#Might be changed to softprops/action-gh-release after additional check
|
||||
- name: Upload release asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: "https://uploads.github.com/repos/actions/runner-images/releases/${{ github.event.client_payload.ReleaseID }}/assets{?name,label}"
|
||||
asset_path: ./sbom.json.zip
|
||||
asset_name: sbom.${{ github.event.client_payload.agentSpec }}.json.zip
|
||||
asset_content_type: application/zip
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
name: macOS image generation
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
image_label:
|
||||
type: string
|
||||
description: macOS codename
|
||||
required: true
|
||||
base_image_name:
|
||||
type: string
|
||||
description: Base clean image
|
||||
required: true
|
||||
template_path:
|
||||
type: string
|
||||
description: Packer template path
|
||||
required: true
|
||||
target_datastore:
|
||||
type: string
|
||||
description: Image datastore
|
||||
required: true
|
||||
custom_repo:
|
||||
type: string
|
||||
description: Custom repo to checkout
|
||||
required: false
|
||||
custom_repo_commit_hash:
|
||||
type: string
|
||||
description: Custom repo commit hash
|
||||
required: false
|
||||
|
||||
env:
|
||||
KEYVAULT: imagegeneration
|
||||
ESXI_CLUSTER: mcv2-build-unstable
|
||||
VCENTER_DATACENTER: imagegen
|
||||
OUTPUT_FOLDER: mms-output
|
||||
BUILD_DATASTORE: ds-image
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
jobs:
|
||||
build:
|
||||
#
|
||||
# "macos-vmware" is dedicated runner not available in forks.
|
||||
# to reduce undesired run attempts in forks, stick jobs to "actions" organization only
|
||||
#
|
||||
runs-on: macos-vmware
|
||||
if: ${{ github.repository_owner == 'actions' }}
|
||||
timeout-minutes: 1200
|
||||
steps:
|
||||
- name: Set image variables
|
||||
run: |
|
||||
$currentDate = Get-Date -Format "yyyyMMdd"
|
||||
$templatePath = "${{ inputs.template_path }}"
|
||||
$osName = $(($templatePath.Split("/")[-1]).Split(".")[0])
|
||||
$virtualMachineName = "${osName}_${currentDate}_unstable.${{ github.run_id }}.${{ github.run_attempt }}"
|
||||
"VM_NAME=$virtualMachineName" | Out-File -Append -FilePath $env:GITHUB_ENV
|
||||
|
||||
- name: Determine checkout type
|
||||
run: |
|
||||
if ("${{ inputs.custom_repo }}" -and "${{ inputs.custom_repo_commit_hash }}") {
|
||||
$checkoutType = "custom_repo"
|
||||
} elseif (("${{ github.event_name }}" -eq "pull_request_target") -and ("${{ github.event.action }}" -eq "labeled" )) {
|
||||
$checkoutType = "pull_request"
|
||||
} else {
|
||||
$checkoutType = "main"
|
||||
}
|
||||
"CHECKOUT_TYPE=$checkoutType" | Out-File -Append $env:GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
if: ${{ env.CHECKOUT_TYPE == 'main' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: actions/runner-images
|
||||
|
||||
- name: Checkout PR
|
||||
if: ${{ env.CHECKOUT_TYPE == 'pull_request' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Checkout custom repository
|
||||
if: ${{ env.CHECKOUT_TYPE == 'custom_repo' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: '${{ inputs.custom_repo }}'
|
||||
ref: '${{ inputs.custom_repo_commit_hash }}'
|
||||
|
||||
- name: Validate contributor permissions
|
||||
if: ${{ github.event_name == 'pull_request_target' }}
|
||||
run: |
|
||||
[string]$contributorAllowList = "${{ vars.CONTRIBUTOR_ALLOWLIST }}"
|
||||
./images.CI/macos/validate-contributor.ps1 `
|
||||
-RepositoryName ${{ github.repository }} `
|
||||
-AccessToken ${{ secrets.GH_FEED }} `
|
||||
-SourceBranch "refs/pull/${{ github.event.pull_request.number }}/merge" `
|
||||
-ContributorAllowList $contributorAllowList
|
||||
|
||||
- name: Select datastore
|
||||
run: |
|
||||
./images.CI/macos/select-datastore.ps1 `
|
||||
-VMName "${{ env.VM_NAME }}" `
|
||||
-VIServer ${{ secrets.VISERVER_V2 }} `
|
||||
-VIUserName ${{ secrets.VI_USER_NAME }} `
|
||||
-VIPassword ${{ secrets.VI_PASSWORD }} `
|
||||
-Cluster ${{ env.ESXI_CLUSTER }}
|
||||
|
||||
- name: Build VM
|
||||
run: |
|
||||
$SensitiveData = @(
|
||||
'IP address:',
|
||||
'Using ssh communicator to connect:'
|
||||
)
|
||||
packer build -on-error=abort `
|
||||
-var="vcenter_server=${{ secrets.VISERVER_V2 }}" `
|
||||
-var="vcenter_username=${{ secrets.VI_USER_NAME }}" `
|
||||
-var="vcenter_password=${{ secrets.VI_PASSWORD }}" `
|
||||
-var="vcenter_datacenter=${{ env.VCENTER_DATACENTER }}" `
|
||||
-var="cluster_or_esxi_host=${{ env.ESXI_CLUSTER }}" `
|
||||
-var="esxi_datastore=${{ env.BUILD_DATASTORE }}" `
|
||||
-var="output_folder=${{ env.OUTPUT_FOLDER }}" `
|
||||
-var="vm_username=${{ secrets.VM_USERNAME }}" `
|
||||
-var="vm_password=${{ secrets.VM_PASSWORD }}" `
|
||||
-var="github_api_pat=${{ secrets.GH_FEED_TOKEN }}" `
|
||||
-var="build_id=${{ env.VM_NAME }}" `
|
||||
-var="baseimage_name=${{ inputs.base_image_name }}" `
|
||||
-var="xcode_install_user=${{ secrets.XCODE_USER }}" `
|
||||
-var="xcode_install_password=${{ secrets.XCODE_PASSWORD }}" `
|
||||
-color=false `
|
||||
${{ inputs.template_path }} `
|
||||
| Where-Object {
|
||||
#Filter sensitive data from Packer logs
|
||||
$currentString = $_
|
||||
$sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ }
|
||||
$sensitiveString -eq $null
|
||||
}
|
||||
working-directory: images/macos
|
||||
env:
|
||||
PACKER_LOG: 1
|
||||
PACKER_LOG_PATH: ${{ runner.temp }}/packer-log.txt
|
||||
|
||||
- name: Prepare artifact
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Preparing artifact directory"
|
||||
mkdir -p ${{ runner.temp }}/artifacts
|
||||
|
||||
echo "Copy image output files"
|
||||
cp -R "images/image-output/software-report/." "${{ runner.temp }}/artifacts"
|
||||
|
||||
echo "Put VM name to 'VM_Done_Name' file"
|
||||
echo "${{ env.VM_NAME }}" > "${{ runner.temp }}/artifacts/VM_Done_Name"
|
||||
|
||||
- name: Print markdown software report
|
||||
run: |
|
||||
Get-Content "${{ runner.temp }}/artifacts/systeminfo.md"
|
||||
|
||||
- name: Print json software report
|
||||
run: |
|
||||
Get-Content "${{ runner.temp }}/artifacts/systeminfo.json"
|
||||
|
||||
- name: Publish Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Built_VM_Artifacts
|
||||
path: ${{ runner.temp }}/artifacts/
|
||||
|
||||
- name: Print provisioners duration
|
||||
run: |
|
||||
./images.CI/measure-provisioners-duration.ps1 `
|
||||
-PackerLogPath "${{ runner.temp }}/packer-log.txt" `
|
||||
-PrintTopNLongest 25
|
||||
|
||||
- name: Move vm to cold storage and clear datastore tag
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
./images.CI/macos/move-vm.ps1 `
|
||||
-VMName "${{ env.VM_NAME }}" `
|
||||
-TargetDataStore "${{ inputs.target_datastore }}" `
|
||||
-VIServer "${{ secrets.VISERVER_V2 }}" `
|
||||
-VIUserName "${{ secrets.VI_USER_NAME }}" `
|
||||
-VIPassword "${{ secrets.VI_PASSWORD }}" `
|
||||
-JobStatus "${{ job.status }}"
|
||||
|
||||
- name: Set VM size
|
||||
run: |
|
||||
$cpuCount = 3
|
||||
$coresPerSocketCount = 3
|
||||
$memory = 14336
|
||||
|
||||
./images.CI/macos/set-vm-size.ps1 `
|
||||
-VMName "${{ env.VM_NAME }}" `
|
||||
-CpuCount "$cpuCount" `
|
||||
-CoresPerSocketCount "$coresPerSocketCount" `
|
||||
-Memory "$memory" `
|
||||
-VIServer "${{ secrets.VISERVER_V2 }}" `
|
||||
-VIUserName "${{ secrets.VI_USER_NAME }}" `
|
||||
-VIPassword "${{ secrets.VI_PASSWORD }}"
|
||||
|
||||
- name: Destroy VM (if build canceled only)
|
||||
if: ${{ cancelled() }}
|
||||
run: |
|
||||
./images.CI/macos/destroy-vm.ps1 `
|
||||
-VMName "${{ env.VM_NAME }}" `
|
||||
-VIServer "${{ secrets.VISERVER_V2 }}" `
|
||||
-VIUserName "${{ secrets.VI_USER_NAME }}" `
|
||||
-VIPassword "${{ secrets.VI_PASSWORD }}"
|
||||
@@ -0,0 +1,30 @@
|
||||
run-name: macOS-11_unstable.${{ github.run_id }}.${{ github.run_attempt }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/macos/**'
|
||||
schedule:
|
||||
- cron: '45 0 * * *'
|
||||
|
||||
jobs:
|
||||
macOS_11:
|
||||
if: ${{ (github.event.label.name == 'CI macos-all') || (github.event.label.name == 'CI macos-11') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
name: macOS-11_unstable.${{ github.run_id }}.${{ github.run_attempt }}
|
||||
uses: ./.github/workflows/macos-generation.yml
|
||||
with:
|
||||
image_label: 'macOS Big Sur'
|
||||
base_image_name: 'clean-macOS-11-380Gb-runner'
|
||||
template_path: 'templates/macOS-11.json'
|
||||
target_datastore: 'ds-image'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,30 @@
|
||||
run-name: macOS-12_unstable.${{ github.run_id }}.${{ github.run_attempt }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/macos/**'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
macOS_12:
|
||||
if: ${{ (github.event.label.name == 'CI macos-all') || (github.event.label.name == 'CI macos-12') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
name: macOS-12_unstable.${{ github.run_id }}.${{ github.run_attempt }}
|
||||
uses: ./.github/workflows/macos-generation.yml
|
||||
with:
|
||||
image_label: 'macOS Monterey'
|
||||
base_image_name: 'clean-macOS-12-380Gb-runner'
|
||||
template_path: 'templates/macOS-12.json'
|
||||
target_datastore: 'ds-image'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -46,14 +46,3 @@ jobs:
|
||||
pull_number: ${{ github.event.client_payload.PullRequestNumber }},
|
||||
merge_method: "squash"
|
||||
})
|
||||
|
||||
- name: Delete docs branch ${{ github.event.client_payload.ReleaseBranchName }}-docs
|
||||
uses: actions/github-script@v2
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
github.git.deleteRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: "heads/${{ github.event.client_payload.ReleaseBranchName }}-docs"
|
||||
})
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# CI Validation
|
||||
|
||||
name: PowerShell Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'helpers/software-report-base/**'
|
||||
|
||||
jobs:
|
||||
powershell-tests:
|
||||
name: PowerShell tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run Software Report module tests
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
Invoke-Pester -Output Detailed "helpers/software-report-base/tests"
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
name: MMS image generation
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
image_name:
|
||||
type: string
|
||||
description: An OS image to build
|
||||
required: true
|
||||
image_readme_name:
|
||||
type: string
|
||||
description: README file path
|
||||
required: true
|
||||
custom_repo:
|
||||
type: string
|
||||
description: Custom repo to checkout
|
||||
required: false
|
||||
custom_repo_commit_hash:
|
||||
type: string
|
||||
description: Custom repo commit hash
|
||||
required: false
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
jobs:
|
||||
build:
|
||||
#
|
||||
# "azure-builds" is dedicated runner not available in forks.
|
||||
# to reduce undesired run attempts in forks, stick jobs to "actions" organization only
|
||||
#
|
||||
runs-on: azure-builds
|
||||
if: ${{ github.repository_owner == 'actions' }}
|
||||
timeout-minutes: 1200
|
||||
steps:
|
||||
- name: Determine checkout type
|
||||
run: |
|
||||
if ("${{ inputs.custom_repo }}" -and "${{ inputs.custom_repo_commit_hash }}") {
|
||||
$checkoutType = "custom_repo"
|
||||
} elseif (("${{ github.event_name }}" -eq "pull_request_target") -and ("${{ github.event.action }}" -eq "labeled" )) {
|
||||
$checkoutType = "pull_request"
|
||||
} else {
|
||||
$checkoutType = "main"
|
||||
}
|
||||
"CHECKOUT_TYPE=$checkoutType" | Out-File -Append $env:GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
if: ${{ env.CHECKOUT_TYPE == 'main' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: actions/runner-images
|
||||
|
||||
- name: Checkout PR
|
||||
if: ${{ env.CHECKOUT_TYPE == 'pull_request' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Checkout custom repository
|
||||
if: ${{ env.CHECKOUT_TYPE == 'custom_repo' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: '${{ inputs.custom_repo }}'
|
||||
ref: '${{ inputs.custom_repo_commit_hash }}'
|
||||
|
||||
- name: Set image varibles
|
||||
run: |
|
||||
$ImageType = "${{ inputs.image_name }}"
|
||||
|
||||
if ($ImageType.StartsWith("ubuntu")) { $TemplateDirectoryName = "linux" } else { $TemplateDirectoryName = "win" }
|
||||
|
||||
$TemplateDirectoryPath = Join-Path "images" $TemplateDirectoryName | Resolve-Path
|
||||
$TemplatePath = Join-Path $TemplateDirectoryPath "$ImageType.pkr.hcl"
|
||||
|
||||
if ( -not (Test-Path $TemplatePath) ) {
|
||||
$TemplatePath = Join-Path $TemplateDirectoryPath "$ImageType.json"
|
||||
}
|
||||
|
||||
"TemplatePath=$TemplatePath" | Out-File -Append -FilePath $env:GITHUB_ENV
|
||||
"TemplateDirectoryPath=$TemplateDirectoryPath" | Out-File -Append -FilePath $env:GITHUB_ENV
|
||||
"ImageType=$ImageType" | Out-File -Append -FilePath $env:GITHUB_ENV
|
||||
|
||||
- name: Build image
|
||||
run: |
|
||||
./images.CI/linux-and-win/build-image.ps1 `
|
||||
-TemplatePath ${{ env.TemplatePath }} `
|
||||
-ClientId ${{ secrets.CLIENT_ID }} `
|
||||
-ClientSecret ${{ secrets.CLIENT_SECRET }} `
|
||||
-Location ${{ secrets.AZURE_LOCATION }} `
|
||||
-ResourcesNamePrefix ${{ github.run_number }} `
|
||||
-ResourceGroup ${{ secrets.AZURE_RESOURCE_GROUP }} `
|
||||
-StorageAccount ${{ secrets.AZURE_STORAGE_ACCOUNT }} `
|
||||
-SubscriptionId ${{ secrets.AZURE_SUBSCRIPTION }} `
|
||||
-TenantId ${{ secrets.AZURE_TENANT }} `
|
||||
-VirtualNetworkName ${{ secrets.BUILD_AGENT_VNET_NAME }} `
|
||||
-VirtualNetworkSubnet ${{ secrets.BUILD_AGENT_SUBNET_NAME }} `
|
||||
-VirtualNetworkRG ${{ secrets.BUILD_AGENT_VNET_RESOURCE_GROUP }} `
|
||||
env:
|
||||
PACKER_LOG: 1
|
||||
PACKER_LOG_PATH: ${{ runner.temp }}/packer-log.txt
|
||||
RUN_VALIDATION_FLAG: true
|
||||
|
||||
- name: Output Readme file content
|
||||
run: |
|
||||
Get-Content -Path (Join-Path "$env:TemplateDirectoryPath" "${{ inputs.image_readme_name }}")
|
||||
|
||||
- name: Print provisioners duration
|
||||
run: |
|
||||
./images.CI/measure-provisioners-duration.ps1 `
|
||||
-PackerLogPath "${{ runner.temp }}/packer-log.txt" `
|
||||
-PrefixToPathTrim ${{ env.TemplateDirectoryPath }} `
|
||||
-PrintTopNLongest 25
|
||||
|
||||
- name: Create release for VM deployment
|
||||
run: |
|
||||
./images.CI/linux-and-win/create-release.ps1 `
|
||||
-BuildId ${{ github.run_number }} `
|
||||
-Organization ${{ secrets.RELEASE_TARGET_ORGANIZATION }} `
|
||||
-DefinitionId ${{ secrets.RELEASE_TARGET_DEFINITION_ID }} `
|
||||
-Project ${{ secrets.RELEASE_TARGET_PROJECT }} `
|
||||
-ImageName ${{ env.ImageType }} `
|
||||
-AccessToken ${{ secrets.RELEASE_TARGET_TOKEN }}
|
||||
|
||||
- name: Clean up resources
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
./images.CI/linux-and-win/cleanup.ps1 `
|
||||
-ResourcesNamePrefix ${{ github.run_number }} `
|
||||
-Image ${{ env.ImageType }} `
|
||||
-StorageAccount ${{ secrets.AZURE_STORAGE_ACCOUNT }} `
|
||||
-SubscriptionId ${{ secrets.AZURE_SUBSCRIPTION }} `
|
||||
-ClientId ${{ secrets.CLIENT_ID }} `
|
||||
-ClientSecret ${{ secrets.CLIENT_SECRET }} `
|
||||
-TenantId ${{ secrets.AZURE_TENANT }}
|
||||
@@ -0,0 +1,27 @@
|
||||
run-name: Ubuntu20.04 - ${{ (github.event.pull_request.title || 'scheduled/manual run') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/linux/**'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
Ubuntu_2004:
|
||||
if: ${{ (github.event.label.name == 'CI ubuntu-all') || (github.event.label.name == 'CI ubuntu-2004') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
uses: ./.github/workflows/ubuntu-win-generation.yml
|
||||
with:
|
||||
image_name: 'ubuntu2004'
|
||||
image_readme_name: 'Ubuntu2004-Readme.md'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,27 @@
|
||||
run-name: Ubuntu22.04 - ${{ (github.event.pull_request.title || 'scheduled/manual run') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/linux/**'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
Ubuntu_2204:
|
||||
if: ${{ (github.event.label.name == 'CI ubuntu-all') || (github.event.label.name == 'CI ubuntu-2204') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
uses: ./.github/workflows/ubuntu-win-generation.yml
|
||||
with:
|
||||
image_name: 'ubuntu2204'
|
||||
image_readme_name: 'Ubuntu2204-Readme.md'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Update release for ${{ github.event.client_payload.ReleaseBranchName }}
|
||||
uses: actions/github-script@v2
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
run-name: Windows 2019 - ${{ (github.event.pull_request.title || 'scheduled/manual run') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/win/**'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
Windows_2019:
|
||||
if: ${{ (github.event.label.name == 'CI windows-all') || (github.event.label.name == 'CI windows-2019') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
uses: ./.github/workflows/ubuntu-win-generation.yml
|
||||
with:
|
||||
image_name: 'windows2019'
|
||||
image_readme_name: 'Windows2019-Readme.md'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,27 @@
|
||||
run-name: Windows 2022 - ${{ (github.event.pull_request.title || 'scheduled/manual run') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
CUSTOM_REPOSITORY:
|
||||
description: 'Custom repository (owner/repo)'
|
||||
required: false
|
||||
CUSTOM_REPOSITORY_COMMIT_HASH:
|
||||
description: 'Commit hash'
|
||||
required: false
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- 'images/win/**'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
Windows_2022:
|
||||
if: ${{ (github.event.label.name == 'CI windows-all') || (github.event.label.name == 'CI windows-2022') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'schedule') }}
|
||||
uses: ./.github/workflows/ubuntu-win-generation.yml
|
||||
with:
|
||||
image_name: 'windows2022'
|
||||
image_readme_name: 'Windows2022-Readme.md'
|
||||
custom_repo: ${{ github.event.inputs.CUSTOM_REPOSITORY }}
|
||||
custom_repo_commit_hash: ${{ github.event.inputs.CUSTOM_REPOSITORY_COMMIT_HASH }}
|
||||
secrets: inherit
|
||||
+7
-1
@@ -267,6 +267,9 @@ paket-files/
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# VSCode settings
|
||||
.vscode/settings.json
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
@@ -387,4 +390,7 @@ public
|
||||
.dynamodb/
|
||||
|
||||
# visual studio code launch configuration
|
||||
launch.json
|
||||
launch.json
|
||||
|
||||
# Ignore dynamic template
|
||||
images/*/*-temp.json
|
||||
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"files.trimTrailingWhitespace": false
|
||||
}
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
## Contributing
|
||||
|
||||
[fork]: https://github.com/actions/virtual-environments/fork
|
||||
[pr]: https://github.com//actions/virtual-environments/compare
|
||||
[fork]: https://github.com/actions/runner-images/fork
|
||||
[pr]: https://github.com//actions/runner-images/compare
|
||||
[code-of-conduct]: CODE_OF_CONDUCT.md
|
||||
|
||||
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
|
||||
@@ -32,13 +32,13 @@ Here are a few things you can do that will increase the likelihood of your pull
|
||||
### General rules
|
||||
- For every new tool add validation scripts and update software report script to make sure that it is included to documentation
|
||||
- If the tool is available in other platforms (macOS, Windows, Linux), make sure you include it in as many as possible.
|
||||
- If installing a few versions of the tool, consider putting the list of versions in the corresponding `toolset.json` file. It will help other customers to configure their builds flexibly. See [toolset-windows-2016.json](images/win/toolsets/toolset-2019.json) as example.
|
||||
- If installing a few versions of the tool, consider putting the list of versions in the corresponding `toolset.json` file. It will help other customers to configure their builds flexibly. See [toolset-windows-2019.json](images/win/toolsets/toolset-2019.json) as example.
|
||||
- Use consistent naming across all files
|
||||
- Validation scripts should be simple and shouldn't change image content
|
||||
|
||||
### Windows
|
||||
- Add a script that will install the tool and put the script in the `scripts/Installers` folder.
|
||||
There are a bunch of helper functions that could simplify your code: `Choco-Install`, `Install-Binary`, `Install-VsixExtension`, `Start-DownloadWithRetry`, `Test-IsWin16`, `Test-IsWin19` (find the full list of helpers in [ImageHelpers.psm1](images/win/scripts/ImageHelpers/ImageHelpers.psm1)).
|
||||
There are a bunch of helper functions that could simplify your code: `Choco-Install`, `Install-Binary`, `Install-VsixExtension`, `Start-DownloadWithRetry`, `Test-IsWin19`, `Test-IsWin22` (find the full list of helpers in [ImageHelpers.psm1](images/win/scripts/ImageHelpers/ImageHelpers.psm1)).
|
||||
- Add a script that will validate the tool installation and put the script in the `scripts/Tests` folder.
|
||||
We use [Pester v5](https://github.com/pester/pester) for validation scripts. If the tests for the tool are complex enough, create a separate `*.Tests.ps1`. Otherwise, use `Tools.Tests.ps1` for simple tests.
|
||||
Add `Invoke-PesterTests -TestFile <testFileName> [-TestName <describeName>]` at the end of the installation script to make sure that your tests will be run.
|
||||
@@ -49,7 +49,7 @@ Add `Invoke-PesterTests -TestFile <testFileName> [-TestName <describeName>]` at
|
||||
Use existing scripts such as [github-cli.sh](images/linux/scripts/installers/github-cli.sh) as a starting point.
|
||||
- Use [helpers](images/linux/scripts/helpers/install.sh) to simplify installation process.
|
||||
- Validation part should `exit 1` if any issue with installation.
|
||||
- Add changes to the software report generator `images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1`. The software report generator is used to generate an image's README file, e.g. [Ubuntu1804-Readme.md](images/linux/Ubuntu1804-README.md) and it uses [MarkdownPS](https://github.com/Sarafian/MarkdownPS).
|
||||
- Add changes to the software report generator `images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1`. The software report generator is used to generate an image's README file, e.g. [Ubuntu2004-Readme.md](images/linux/Ubuntu2004-README.md) and it uses [MarkdownPS](https://github.com/Sarafian/MarkdownPS).
|
||||
|
||||
### macOS
|
||||
macOS source lives in this repository and available for everyone. However, macOS image-generation CI doesn't support external contributions yet so we are not able to accept pull-requests for now.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 GitHub
|
||||
Copyright (c) 2023 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,59 +1,202 @@
|
||||
# GitHub Actions Virtual Environments
|
||||
This repository contains the source used to create the [virtual environments](https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners) for GitHub Actions hosted runners, as well as the VM images of [Microsoft-hosted agents](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops#use-a-microsoft-hosted-agent) used for Azure Pipelines. To build a VM machine from this repo's source, see the [instructions](docs/create-image-and-azure-resources.md).
|
||||
|
||||
How to get in touch with us:
|
||||
- To file a bug report, or request tools to be added/updated, please [open an issue using the appropriate template](https://github.com/actions/virtual-environments/issues/new/choose)
|
||||
- If you want to share your thoughts about image configuration, installed software, or bring some idea, please, create a new topic in a [discussions section](https://github.com/actions/virtual-environments/discussions) for a corresponding category. Before making a new discussion please make sure no similar topics were created earlier.
|
||||
# GitHub Actions Runner Images
|
||||
|
||||
For general questions about using the virtual environments or writing your Actions workflow, please open requests in the [GitHub Actions Community Forum](https://github.community/c/github-actions/41).
|
||||
**Table of Contents**
|
||||
|
||||
## Available Environments
|
||||
| Environment | YAML Label | Included Software | Latest Release & Rollout Progress |
|
||||
- [About](#about)
|
||||
- [Available Images](#available-images)
|
||||
- [Announcements](#announcements)
|
||||
- [Image Definitions](#image-definitions)
|
||||
- [Image Releases](#image-releases)
|
||||
- [Software and Image Support](#software-and-image-support)
|
||||
- [How to Interact with the Repo](#how-to-interact-with-the-repo)
|
||||
- [FAQs](#faqs)
|
||||
|
||||
## About
|
||||
|
||||
This repository contains the source code used to create the VM images for [GitHub-hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners) used for Actions, as well as for [Microsoft-hosted agents](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops#use-a-microsoft-hosted-agent) used for Azure Pipelines.
|
||||
To build a VM machine from this repo's source, see the [instructions](docs/create-image-and-azure-resources.md).
|
||||
|
||||
## Available Images
|
||||
|
||||
| Image | YAML Label | Included Software | Rollout Progress of Latest Image Release |
|
||||
| --------------------|---------------------|--------------------|---------------------|
|
||||
| Ubuntu 20.04 | `ubuntu-latest` or `ubuntu-20.04` | [ubuntu-20.04] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=ubuntu20&redirect=1)
|
||||
| Ubuntu 18.04 | `ubuntu-18.04` | [ubuntu-18.04] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=ubuntu18&redirect=1)
|
||||
| macOS 11 | `macos-11` | [macOS-11] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=macos-11&redirect=1)
|
||||
| macOS 10.15 | `macos-latest` or `macos-10.15` | [macOS-10.15] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=macos-10.15&redirect=1)
|
||||
| Windows Server 2022 | `windows-2022` | [windows-2022] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=windows-2022&redirect=1) |
|
||||
| Windows Server 2019 | `windows-latest` or `windows-2019` | [windows-2019] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=windows-2019&redirect=1)
|
||||
| Windows Server 2016 | `windows-2016` | [windows-2016] | [](https://actionvirtualenvironmentsstatus.azurewebsites.net/api/status?imageName=windows-2016&redirect=1)
|
||||
| Ubuntu 22.04 | `ubuntu-latest` or `ubuntu-22.04` | [ubuntu-22.04] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=ubuntu22&redirect=1)
|
||||
| Ubuntu 20.04 | `ubuntu-20.04` | [ubuntu-20.04] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=ubuntu20&redirect=1)
|
||||
| macOS 13 [beta] | `macos-13` or `macos-13-xl`| [macOS-13] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=macos-13&redirect=1)
|
||||
| macOS 12 | `macos-latest`, `macos-latest-xl`, `macos-12`, or `macos-12-xl`| [macOS-12] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=macos-12&redirect=1)
|
||||
| macOS 11 | `macos-11`| [macOS-11] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=macos-11&redirect=1)
|
||||
| Windows Server 2022 | `windows-latest` or `windows-2022` | [windows-2022] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=windows-2022&redirect=1) |
|
||||
| Windows Server 2019 | `windows-2019` | [windows-2019] | [](https://runnerimagesdeploymentstatus.azurewebsites.net/api/status?imageName=windows-2019&redirect=1)
|
||||
|
||||
<b>Note:</b> Beta and Preview images are provided "as-is", "with all faults" and "as available" and are excluded from the service level agreement and warranty. Beta and Preview images may not be covered by customer support.
|
||||
### Label scheme
|
||||
|
||||
***What images are available for GitHub Actions and Azure DevOps?***
|
||||
The availability of images for GitHub Actions and Azure DevOps is different. See documentation for more details:
|
||||
- [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources)
|
||||
- [Azure DevOps](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#software)
|
||||
- In general the `-latest` label is used for the latest OS image version that is GA
|
||||
- Before moving the`-latest` label to a new OS version we will announce the change and give sufficient lead time for users to update their workflows
|
||||
|
||||
***What image version is used in my build?*** Usually, image deployment takes 3-4 days, and documentation in the `main` branch is only updated when deployment is finished. To find out which image version and what software versions are used in a specific build, see `Set up job` (GitHub Actions) or `Initialize job` (Azure DevOps) step log.
|
||||
|
||||
***Looking for other Linux distributions?*** We do not plan to offer other Linux distributions. We recommend using Docker if you'd like to build using other distributions with the hosted virtual environments. Alternatively, you can leverage [self-hosted runners] and fully customize your environment to your needs.
|
||||
|
||||
***How to contribute to macOS source?*** macOS source lives in this repository and available for everyone. However, MacOS image-generation CI doesn't support external contributions yet so we are not able to accept pull-requests for now.
|
||||
We are in the process of preparing MacOS CI to accept contributions. Until then, we appreciate your patience and ask you continue to make tool requests by filing issues.
|
||||
|
||||
## Updates to virtual environments
|
||||
*Cadence*
|
||||
|
||||
We typically deploy weekly updates to the software on the virtual environments.
|
||||
For some tools, we always install the latest at the time of the deployment; for others,
|
||||
we pin the tool to specific version(s).
|
||||
|
||||
*Following Along / Change Notifications*
|
||||
|
||||
* **High Impact Changes** (ex. breaking changes, new or deprecated environments) will be posted to the GitHub Changelog on our [blog](https://github.blog/changelog/) and on [twitter](https://twitter.com/GHchangelog).
|
||||
* **Low Impact Changes** will be pinned in this repository and marked with the [Announcement](https://github.com/actions/virtual-environments/labels/Announcement) label.
|
||||
* **Regular Weekly Rhythm** can be followed by watching [Releases](https://github.com/actions/virtual-environments/releases). Pre-release is created when deployment is started. As soon as deployment is finished, it is converted to release.
|
||||
You can also track upcoming changes using the [awaiting-deployment](https://github.com/actions/virtual-environments/labels/awaiting-deployment) label.
|
||||
|
||||
[ubuntu-20.04]: https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md
|
||||
[ubuntu-18.04]: https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu1804-Readme.md
|
||||
[windows-2022]: https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md
|
||||
[windows-2019]: https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md
|
||||
[windows-2016]: https://github.com/actions/virtual-environments/blob/main/images/win/Windows2016-Readme.md
|
||||
[macOS-11]: https://github.com/actions/virtual-environments/blob/main/images/macos/macos-11-Readme.md
|
||||
[macOS-10.15]: https://github.com/actions/virtual-environments/blob/main/images/macos/macos-10.15-Readme.md
|
||||
[ubuntu-22.04]: https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md
|
||||
[ubuntu-20.04]: https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md
|
||||
[windows-2022]: https://github.com/actions/runner-images/blob/main/images/win/Windows2022-Readme.md
|
||||
[windows-2019]: https://github.com/actions/runner-images/blob/main/images/win/Windows2019-Readme.md
|
||||
[macOS-11]: https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md
|
||||
[macOS-12]: https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md
|
||||
[macOS-13]: https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md
|
||||
[macOS-10.15]: https://github.com/actions/runner-images/blob/main/images/macos/macos-10.15-Readme.md
|
||||
[self-hosted runners]: https://help.github.com/en/actions/hosting-your-own-runners
|
||||
|
||||
## Software and image guidelines
|
||||
To learn more about tools and images support policy, see the [guidelines](./docs/software-and-images-guidelines.md).
|
||||
## Announcements
|
||||
|
||||
See notable upcoming changes by viewing issues with the [Announcement](https://github.com/actions/runner-images/labels/Announcement) label.
|
||||
|
||||
## Image Definitions
|
||||
|
||||
### Beta
|
||||
|
||||
The purpose of a Beta is to collect feedback on an image before it is released to GA. The goal of a Beta is to identify and fix any potential issues that exist on that
|
||||
image. Images are updated on a weekly cadence. Any workflows that run on a beta image do not fall under the customer [SLA](https://github.com/customer-terms/github-online-services-sla) in place for Actions.
|
||||
Customers choosing to use Beta images are encouraged to provide feedback in the runner-images repo by creating an issue. A Beta may take on different availability, i.e. public vs private.
|
||||
|
||||
### GA
|
||||
|
||||
A GA (General Availability) image has been through a Beta period and is deemed ready for general use. Images are updated on a weekly cadence. In order to be moved to
|
||||
GA the image must meet the following criteria:
|
||||
|
||||
1. Has been through a Beta period (public or private)
|
||||
2. Most major software we install on the image has a compatible
|
||||
version for the underlying OS and
|
||||
3. All major bugs reported during the Beta period have been addressed.
|
||||
|
||||
This image type falls under the customer [SLA](https://github.com/customer-terms/github-online-services-sla) for actions. GA images are eventually deprecated according to our guidelines as we only support the
|
||||
latest 2 versions of an OS.
|
||||
|
||||
#### Latest Migration Process
|
||||
|
||||
GitHub Actions and Azure DevOps use the `-latest` YAML label (ex: `ubuntu-latest`, `windows-latest`, and `macos-latest`). These labels point towards the newest stable OS version available.
|
||||
|
||||
|
||||
The `-latest` migration process is gradual and happens over 1-2 months in order to allow customers to adapt their workflows to the newest OS version. During this process, any workflow using the `-latest` label, may see changes in the OS version in their workflows or pipelines. To avoid unwanted migration, users can specify a specific OS version in the yaml file (ex: macos-12, windows-2022, ubuntu-22.04).
|
||||
|
||||
|
||||
## Image Releases
|
||||
|
||||
*How to best follow along with changes*
|
||||
|
||||
1. Find the latest releases for this repository [here.](https://github.com/actions/runner-images/releases)
|
||||
2. Subscribe to the releases coming out of this repository, instructions [here.](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)
|
||||
3. Upcoming changes: A pre-release is created when the deployment of an image has started. As soon as the deployment is finished, the pre-release is converted to a release. If you have subscribed to releases, you will get notified of pre-releases as well.
|
||||
|
||||
- You can also track upcoming changes using the [awaiting-deployment](https://github.com/actions/runner-images/labels/awaiting-deployment) label.
|
||||
4. For high impact changes, we will post these in advance to the GitHub Changelog on our [blog](https://github.blog/changelog/) and on [twitter](https://twitter.com/GHchangelog).
|
||||
- Ex: breaking changes, GA or deprecation of images
|
||||
|
||||
*Cadence*
|
||||
|
||||
- We typically deploy weekly updates to the software on the runner images.
|
||||
|
||||
## Software and Image Support
|
||||
|
||||
### Support Policy
|
||||
|
||||
- Tools and versions will typically be removed 6 months after they are deprecated or have reached end-of-life
|
||||
- We support (at maximum) 2 GA images and 1 beta image at a time. We begin the deprecation process of the oldest image label once the newest OS image label has been released to GA.
|
||||
- The images generally contain the latest versions of packages installed except for Ubuntu LTS where we mostly rely on the Canonical-provided repositories.
|
||||
|
||||
- Popular tools can have several versions installed side-by-side with the following strategy:
|
||||
|
||||
| Tool name | Installation strategy |
|
||||
|-----------|-----------------------|
|
||||
| Docker images | not more than 3 latest LTS OS\tool versions. New images or new versions of current images are added using the standard tool request process |
|
||||
| Java | all LTS versions |
|
||||
| Node.js | 3 latest LTS versions |
|
||||
| Go | 3 latest minor versions |
|
||||
| Python <br/> Ruby | 5 most popular `major.minor` versions |
|
||||
| PyPy | 3 most popular `major.minor` versions |
|
||||
| .NET Core | 2 latest LTS versions and 1 latest version. For each feature version only latest patch is installed |
|
||||
| GCC <br/> GNU Fortran <br/> Clang <br/> GNU C++ | 3 latest major versions |
|
||||
| Android NDK | 1 latest non-LTS, 2 latest LTS versions |
|
||||
| Xcode | - all OS compatible versions side-by-side <br/> - for beta, GM versions - latest beta only <br/> - old patch versions are deprecated in 3 months |
|
||||
|
||||
### Package managers usage
|
||||
|
||||
We use third-party package managers to install software during the image generation process. The table below lists the package managers and the software installed.
|
||||
> **Note**: third-party repositories are re-evaluated every year to identify if they are still useful and secure.
|
||||
|
||||
| Operating system | Package manager | Third-party repos and packages |
|
||||
| :--- | :---: | ---: |
|
||||
| Ubuntu | [APT](https://wiki.debian.org/Apt) | [Eclipse-Temurin (Adoptium)](https://packages.adoptium.net/artifactory/deb) </br> [Erlang](https://packages.erlang-solutions.com/ubuntu) </br>[Firefox](https://launchpad.net/~mozillateam/+archive/ubuntu/ppa) </br> [gcc, gfortran](https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test) </br> [git](https://launchpad.net/~git-core/+archive/ubuntu/ppa) </br> [HHvm](https://dl.hhvm.com/ubuntu) </br> [PHP](https://launchpad.net/~ondrej/+archive/ubuntu/php) (Ubuntu 20 only) </br> [Mono](https://download.mono-project.com/repo/ubuntu) </br> [PostgreSQL](https://apt.postgresql.org/pub/repos/apt) </br> [R](https://cloud.r-project.org/bin/linux/ubuntu) |
|
||||
| | [pipx](https://pypa.github.io/pipx) | ansible-core </br>yamllint |
|
||||
| Windows | [Chocolatey](https://chocolatey.org) | No third-party repos installed |
|
||||
| macOS | [Homebrew](https://brew.sh) | [aws-cli v2](https://github.com/aws/homebrew-tap) </br> [azure/bicep](https://github.com/Azure/homebrew-bicep) </br> [mongodb/brew](https://github.com/mongodb/homebrew-brew) |
|
||||
| | [pipx](https://pypa.github.io/pipx/) | yamllint |
|
||||
|
||||
### Image Deprecation Policy
|
||||
|
||||
- Images begin the deprecation process of the oldest image label once a new GA OS version has been released.
|
||||
- Deprecation process begins with an announcement that sets a date for deprecation
|
||||
- As it gets closer to the date, GitHub begins doing scheduled brownouts of the image
|
||||
- During this time there will be an Announcement pinned in the repo to remind users of the deprecation.
|
||||
- Finally GitHub will deprecate the image and it will no longer be available
|
||||
|
||||
### Preinstallation Policy
|
||||
|
||||
In general, these are the guidelines we follow when deciding what to pre-install on our images:
|
||||
|
||||
- Popularity: widely-used tools and ecosystems will be given priority.
|
||||
- Latest Technology: recent versions of tools will be given priority.
|
||||
- Deprecation: end-of-life tools and versions will not be added.
|
||||
- Licensing: MIT, Apache, or GNU licenses are allowed.
|
||||
- Time & Space on the Image: we will evaluate how much time is saved and how much space is used by having the tool pre-installed.
|
||||
- Support: If a tool requires the support of more than one version, we will consider the cost of this maintenance.
|
||||
|
||||
### Default Version Update Policy
|
||||
|
||||
- In general, once a new version is installed on the image, we announce the default version update 2 weeks prior to deploying it.
|
||||
- For potentially dangerous updates, we may extend the timeline up to 1 month between the announcement and deployment.
|
||||
|
||||
## How to Interact with the Repo
|
||||
|
||||
- **Issues**: To file a bug report, or request tools to be added/updated, please [open an issue using the appropriate template](https://github.com/actions/runner-images/issues/new/choose)
|
||||
- **Discussions**: If you want to share your thoughts about image configuration, installed software, or bring a new idea, please create a new topic in a [discussion](https://github.com/actions/runner-images/discussions) for a corresponding category. Before making a new discussion please make sure no similar topics were created earlier.
|
||||
- For general questions about using the runner images or writing your Actions workflow, please open requests in the [GitHub Actions Community Forum](https://github.community/c/github-actions/41).
|
||||
|
||||
## FAQs
|
||||
|
||||
<details>
|
||||
<summary><b><i>What images are available for GitHub Actions and Azure DevOps?</b></i></summary>
|
||||
|
||||
The availability of images for GitHub Actions and Azure DevOps is the same. However, deprecation policies may differ. See documentation for more details:
|
||||
- [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources)
|
||||
- [Azure DevOps](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#software)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><i>What image version is used in my build?</b></i></summary>
|
||||
|
||||
Usually, image deployment takes 2-3 days, and documentation in the `main` branch is only updated when deployment is finished. To find out which image version and what software versions are used in a specific build, see `Set up job` (GitHub Actions) or `Initialize job` (Azure DevOps) step log.
|
||||
<img width="1440" alt="actions-runner-image" src="https://user-images.githubusercontent.com/56982181/169595536-91a8a79b-d5e0-47d1-a736-510cff6cfb83.png">
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><i>Looking for other Linux distributions?</b></i></summary>
|
||||
|
||||
We do not plan to offer other Linux distributions. We recommend using Docker if you'd like to build using other distributions with the hosted runner images. Alternatively, you can leverage [self-hosted runners] and fully customize your VM image to your needs.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><i>How do I contribute to the macOS source?</b></i></summary>
|
||||
|
||||
macOS source lives in this repository and is available for everyone. However, macOS image-generation CI doesn't support external contributions yet so we are not able to accept pull-requests for now.
|
||||
|
||||
We are in the process of preparing macOS CI to accept contributions. Until then, we appreciate your patience and ask you to continue to make tool requests by filing issues.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><i>How does GitHub determine what tools are installed on the images?</b></i></summary>
|
||||
|
||||
For some tools, we always install the latest at the time of the deployment; for others, we pin the tool to specific version(s). For more details please see the [Preinstallation Policy](#preinstallation-policy)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><i>How do I request that a new tool be pre-installed on the image?</b></i></summary>
|
||||
Please create an issue and get an approval from us to add this tool to the image before creating the pull request.
|
||||
</details>
|
||||
|
||||
@@ -1,93 +1,178 @@
|
||||
# Virtual-Environments
|
||||
The virtual-environments project uses [Packer](https://www.packer.io/) to generate disk images for the following platforms: Windows 2016/2019/2022, Ubuntu 18.04/20.04.
|
||||
Each image is configured through a JSON template that Packer understands and which specifies where to build the image (Azure in this case), and what scripts to run to install software and prepare the disk.
|
||||
The Packer process initializes a connection to Azure subscription via Azure CLI, and automatically creates the temporary Azure resources required to build the source VM(temporary resource group, network interfaces, and VM from the "clean" image specified in the template).
|
||||
If the VM deployment succeeds, the build agent connects to the VM and starts to execute installation steps from the JSON template.
|
||||
If any step in the JSON template fails, image generation will be aborted and the temporary VM will be terminated. Packer will also attempt to cleanup all the temporary resources it created (unless otherwise told).
|
||||
After successful image generation, a snapshot of the temporary VM will be converted to VHD image and then uploaded to the specified Azure Storage Account.
|
||||
# GitHub Actions Runner Images
|
||||
|
||||
## Prerequisites and Image-generation
|
||||
### Build Agent requirements
|
||||
- `OS` - Windows/Linux
|
||||
- `packer` - Can be downloaded from https://www.packer.io/downloads
|
||||
- `PowerShell 5.0 or higher` or `PSCore` for linux distributes.
|
||||
- `Azure CLI ` - https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
|
||||
- `Azure Az Powershell module` - https://docs.microsoft.com/en-us/powershell/azure/install-az-ps
|
||||
- `Git for Windows` - https://gitforwindows.org/
|
||||
The runner-images project uses [Packer](https://www.packer.io/) to generate disk images for Windows 2019/2022 and Ubuntu 20.04/22.04.
|
||||
|
||||
> To connect to a temporary VM packer uses WinRM or SSH connections on public IP interfaces.
|
||||
If you use a build agent located in an Azure subscription, please make sure that HTTPS/SSH ports are allowed for incoming/outgoing connections.
|
||||
In case of firewall restrictions, prohibiting connections from public addresses, private virtual network resources can be deployed and passed as arguments to the packer. This approach allows virtual machines to use private connections inside VLAN.
|
||||
Each image is configured by a JSON or HCL2 Packer template that specifies where to build the image (Azure in this case)
|
||||
and what steps to run to install software and prepare the disk.
|
||||
|
||||
### Service principal
|
||||
Packer uses Service Principal to authorize in Azure infrastructure. To setup image-generation CI or use packer manually — SP with full read-write permissions for selected Azure subscription needed.
|
||||
Detailed instruction can be found in [Azure documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal)
|
||||
The Packer process initializes a connection to Azure subscription using Azure CLI and creates temporary resources
|
||||
required for the build process: resource group, network interfaces and virtual machine from the "clean" image specified in the template.
|
||||
|
||||
### Prepare environment and image deployment
|
||||
#### How to prepare Windows build agent
|
||||
Local machine or [Azure VM](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/quick-create-cli) can be used as a build agent.
|
||||
If the VM deployment succeeds, Packer connects it using ssh or WinRM and begins executing installation steps from the template one-by-one.
|
||||
If any step fails, image generation is aborted and the temporary VM is terminated.
|
||||
Packer also attempts to cleanup all the temporary resources it created (unless otherwise configured).
|
||||
|
||||
Download `packer` from https://www.packer.io/downloads, or install it via Chocolately.
|
||||
```
|
||||
choco install packer
|
||||
After successful completion of all installation steps Packer converts snapshot of the temporary VM to VHD image
|
||||
and uploads it to the specified Azure Storage Account.
|
||||
|
||||
## Build agent preparation
|
||||
|
||||
Build agent is a machine where Packer process will be started.
|
||||
You can use any physical or virtual machine running OS Windows or Linux.
|
||||
Of course you may also use [Azure VM](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/quick-create-cli).
|
||||
In any case you will need these software installed:
|
||||
|
||||
- Packer 1.8.2 or higher.
|
||||
|
||||
Download and install it manually from [here](https://www.packer.io/downloads) or use [Chocolatey](https://chocolatey.org/):
|
||||
|
||||
```powershell
|
||||
choco install packer
|
||||
```
|
||||
|
||||
- Git.
|
||||
|
||||
For Linux - install the latest version from your distro's package repo.
|
||||
|
||||
For Windows - download and install it from [here](https://gitforwindows.org/) of use [Chocolatey](https://chocolatey.org/):
|
||||
|
||||
```powershell
|
||||
choco install git -params '"/GitAndUnixToolsOnPath"'
|
||||
```
|
||||
|
||||
- Powershell 5.0 or higher.
|
||||
|
||||
In Windows you already have it.
|
||||
|
||||
For Linux follow instructions [here](https://learn.microsoft.com/en-us/windows-server/administration/linux-package-repository-for-microsoft-software)
|
||||
to add Microsoft's Linux Software Repository and then install package `powershell`.
|
||||
- Azure CLI.
|
||||
|
||||
Follow instructions [here](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).
|
||||
Or if you use Windows you may run this command in Powershell instead:
|
||||
|
||||
```powershell
|
||||
Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi
|
||||
Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi
|
||||
```
|
||||
|
||||
- [Az Powershell module](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps).
|
||||
|
||||
Run this command in Powershell:
|
||||
|
||||
```powershell
|
||||
Install-Module -Name Az -Repository PSGallery -Force
|
||||
```
|
||||
|
||||
## Automated image generation
|
||||
|
||||
This repo bundles script that automates image generation process.
|
||||
You only need a build agent configured as described above and active Azure subsctiption.
|
||||
We suggest to start with UbuntuMinimal image because it includes only a minimal set of required software and builds in less then half an hour.
|
||||
|
||||
All steps here are supposed to run in Powershell.
|
||||
|
||||
First, clone runner-images repository and change directory:
|
||||
|
||||
```powershell
|
||||
git clone https://github.com/actions/runner-images.git
|
||||
Set-Location runner-images
|
||||
```
|
||||
|
||||
Install the Azure Az PowerShell module - https://docs.microsoft.com/en-us/powershell/azure/install-az-ps.
|
||||
```
|
||||
Install-Module -Name Az -Repository PSGallery -Force
|
||||
```
|
||||
|
||||
Install Azure CLI - https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest&tabs=azure-cli.
|
||||
```
|
||||
Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi
|
||||
```
|
||||
|
||||
Download Virtual-Environments repository.
|
||||
```
|
||||
Set-Location c:\
|
||||
git clone https://github.com/actions/virtual-environments.git
|
||||
```
|
||||
|
||||
Import [GenerateResourcesAndImage](../helpers/GenerateResourcesAndImage.ps1) script from `/helpers` folder, and run `GenerateResourcesAndImage` function via Powershell.
|
||||
|
||||
```
|
||||
Set-Location C:\virtual-environments
|
||||
Then import [GenerateResourcesAndImage](../helpers/GenerateResourcesAndImage.ps1) script from `helpers` subdirectory:
|
||||
|
||||
```powershell
|
||||
Import-Module .\helpers\GenerateResourcesAndImage.ps1
|
||||
|
||||
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "myTestResourceGroup" -ImageGenerationRepositoryRoot "$pwd" -ImageType Ubuntu1804 -AzureLocation "East US"
|
||||
```
|
||||
Where:
|
||||
- `SubscriptionId` - The Azure subscription Id where resources will be created.
|
||||
- `ResourceGroupName` - The Azure resource group name where the Azure resources will be created.
|
||||
- `ImageGenerationRepositoryRoot` - The root path of the image generation repository source.
|
||||
- `ImageType` - The type of the image being generated. Valid options are: "Windows2016", "Windows2019", "Windows2022", "Ubuntu1804", "Ubuntu2004".
|
||||
- `AzureLocation` - The location of the resources being created in Azure. For example "East US".
|
||||
|
||||
The function automatically creates all required Azure resources and kicks off packer image generation for the selected image type.
|
||||
|
||||
For optional authentication via service principal make sure to provide the following params — `AzureClientId`, `AzureClientSecret`, `AzureTenantId`, so the whole command will be:
|
||||
|
||||
```
|
||||
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "myTestResourceGroup" -ImageGenerationRepositoryRoot "$pwd" -ImageType Ubuntu1804 -AzureLocation "East US" -AzureClientId {AADApplicationID} -AzureClientSecret {AADApplicationSecret} -AzureTenantId {AADTenantID}
|
||||
```
|
||||
|
||||
*Please, check synopsis of `GenerateResourcesAndImage` for details about non-mandatory parameters.*
|
||||
Finally, run `GenerateResourcesAndImage` function setting mandatory arguments: image type and where to create resources:
|
||||
|
||||
- `SubscriptionId` - your Azure Subscription ID
|
||||
- `ResourceGroupName` - name of the resource group that will be created within your subscription (e.g. "imagegen-test")
|
||||
- `AzureLocation` - location where resources will be created (e.g. "East US")
|
||||
- `ImageType` - what image to build (we suggest choosing "UbuntuMinimal" here, other valid options are "Windows2019", "Windows2022", "Ubuntu2004", "Ubuntu2204")
|
||||
|
||||
> :warning: When running `GenerateResourcesAndImage` in PowerShell 7.3, following command should be executed first:
|
||||
> ```powershell
|
||||
> $PSNativeCommandArgumentPassing = 'Legacy'
|
||||
> ```
|
||||
|
||||
This function automatically creates all required Azure resources and kicks off packer image generation for the selected image type.
|
||||
|
||||
When image is ready you may proceed to [deployment](#generated-machine-deployment)
|
||||
|
||||
## Image generation customization
|
||||
|
||||
Function `GenerateResourcesAndImage` accepts a bunch of arguments that may help you generating image in your specific environment.
|
||||
|
||||
For example, you may want that all the resources involved in image generation process are tagged.
|
||||
In this case pass a HashTable of tags as a value for `Tags` parameter.
|
||||
|
||||
If you don't want function to authenticate interactively, you should create Service Principal and invoke the function with parameters `AzureClientId`, `AzureClientSecret` and `AzureTenantId`.
|
||||
You can find more details [in corresponding section below](#azure-subscription-authentication).
|
||||
|
||||
Use `get-help GenerateResourcesAndImage -Detailed` for the complete list of parameters available.
|
||||
|
||||
### Network security
|
||||
|
||||
To connect to a temporary virtual machine Packer uses WinRM or SSH.
|
||||
|
||||
If your build agent is located outside of the Azure subscription where temporary VM is created, the public network interface and public IP address is used.
|
||||
Make sure that firewalls are configured properly and WinRM (tcp port 5986) and ssh (tcp port 22) connections are allowed both outgoing for build agent and incoming for temporary VM.
|
||||
Also if you don't want temporary VM to be accessible from everywhere, set `RestrictToAgentIpAddress` parameter value to `$true`
|
||||
to setup firewall rules allowing access only from your build agent public IP address.
|
||||
|
||||
If your build agent and temporary VM are in the same subscription you can configure Packer to connect using private virtual network.
|
||||
To achieve that set proper values for environment variables `VNET_RESOURCE_GROUP`, `VNET_NAME` and `VNET_SUBNET`.
|
||||
|
||||
### Azure subscription authentication
|
||||
|
||||
Packer uses Service Principal to authenticate in Azure infrastructure.
|
||||
For more information about Service Principals refer to
|
||||
[Azure documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal).
|
||||
|
||||
Function `GenerateResourcesAndImage` is able to create Service Principle to be used by Packer.
|
||||
It uses Connect-AzAccount cmdlet that invokes interactive authentication process by default.
|
||||
If you don't want to use interactive authentication you should create Service Principal with full read-write permissions for selected Azure subscription on your own
|
||||
and provide proper values for parameters `AzureClientId`, `AzureClientSecret` and `AzureTenantId`.
|
||||
|
||||
Here is an example of how to create Service Principle using Az Powershell module:
|
||||
|
||||
```powershell
|
||||
$credentials = [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential]@{
|
||||
StartDateTime = Get-Date
|
||||
EndDateTime = (Get-Date).AddDays(7)
|
||||
}
|
||||
|
||||
$sp = New-AzADServicePrincipal -DisplayName "imagegen-app"
|
||||
$appCred = New-AzADAppCredential -ApplicationId $sp.AppId -PasswordCredentials $credentials
|
||||
|
||||
Start-Sleep -Seconds 30
|
||||
New-AzRoleAssignment -RoleDefinitionName "Contributor" -PrincipalId $sp.Id
|
||||
Start-Sleep -Seconds 30
|
||||
|
||||
@{
|
||||
ClientId = $sp.AppId
|
||||
ClientSecret = $appCred.SecretText
|
||||
TenantId = (Get-AzSubscription -SubscriptionId $SubscriptionId).TenantId
|
||||
}
|
||||
```
|
||||
|
||||
## Generated machine deployment
|
||||
|
||||
#### Generated VM Deployment
|
||||
After the successful image generation, Virtual Machine can be created from the generated VHD using [CreateAzureVMFromPackerTemplate](../helpers/CreateAzureVMFromPackerTemplate.ps1) script.
|
||||
|
||||
```
|
||||
Set-Location C:\virtual-environments
|
||||
|
||||
```powershell
|
||||
Import-Module .\helpers\CreateAzureVMFromPackerTemplate.ps1
|
||||
|
||||
CreateAzureVMFromPackerTemplate -SubscriptionId {YourSubscriptionId} -ResourceGroupName {ResourceGroupName} -TemplateFile "C:\BuildVmImages\temporaryTemplate.json" -VirtualMachineName "testvm1" -AdminUsername "shady1" -AdminPassword "SomeSecurePassword1" -AzureLocation "eastus"
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `SubscriptionId` - The Azure subscription Id where resources will be created.
|
||||
- `ResourceGroupName` - The Azure resource group name where the Azure virtual machine will be created.
|
||||
- `TemplateFilePath` - The path to the json ARM-template generated by packer during image generation locally.*
|
||||
- `TemplateFilePath` - The path to the json ARM-template generated by packer during image generation locally.*
|
||||
- `VirtualMachineName` - The name of the virtual machine to be generated.
|
||||
- `AdminUserName` - The administrator username for the virtual machine to be created.
|
||||
- `AdminPassword` - The administrator password for the virtual machine to be created.
|
||||
@@ -97,19 +182,27 @@ Where:
|
||||
|
||||
The function creates an Azure VM from a template and generates network resources in Azure to make the VM accessible.
|
||||
|
||||
## Additional
|
||||
### User variables
|
||||
The Packer template includes `variables` section containing user variables used in image generation. Each variable is defined as a key/value strings. User variables can be passed to packer via predefined environment variables, or as direct arguments, in case if packer started manually.
|
||||
## Manual image generation
|
||||
|
||||
If you want more control over image generation process you may run Packer directly. This section describes variables defined in Packer template. Some of them may be set using environment variabes.
|
||||
|
||||
### Required variables
|
||||
|
||||
| Template var | Env var | Description
|
||||
| ------------ | ------- | -----------
|
||||
| `subscription_id` | `ARM_SUBSCRIPTION_ID` | Subscription under which the build will be performed.
|
||||
| `client_id` | `ARM_CLIENT_ID` | The Active Directory service principal associated with your builder.
|
||||
| `client_secret` | `ARM_CLIENT_SECRET` | The password or secret for your service principal; may be omitted if `client_cert_path` is set.
|
||||
| `client_cert_path` | `ARM_CLIENT_CERT_PATH` | The location of a PEM file containing a certificate and private key for service principal; may be omitted if `client_secret` is set.
|
||||
| `location` | `ARM_RESOURCE_LOCATION` | Azure datacenter in which your VM will build.
|
||||
| `resource_group` | `ARM_RESOURCE_GROUP` | Resource group under which the final artifact will be stored.
|
||||
| `storage_account` | `ARM_STORAGE_ACCOUNT` | Storage account under which the final artifact will be stored.
|
||||
|
||||
### Optional variables
|
||||
|
||||
- `build_resource_group_name` - Specify an existing resource group to run the build in it. By default, a temporary resource group will be created and destroyed as part of the build. If you do not have permission to do so, use build_resource_group_name to specify an existing resource group to run the build in it.
|
||||
- `client_id` - The application ID of the AAD Service Principal. Requires `client_secret`.
|
||||
- `object_id` - The object ID for the AAD SP. Will be derived from the oAuth token if empty.
|
||||
- `client_secret` - A password/secret registered for the AAD SP.
|
||||
- `subscription_id` - The subscription to use.
|
||||
- `tenant_id` - The Active Directory tenant identifier with which your `client_id` and `subscription_id` are associated. If not specified, `tenant_id` will be looked up using `subscription_id`.
|
||||
- `resource_group` - Resource group under which the final artifact will be stored.
|
||||
- `storage_account` - Storage account under which the final artifact will be stored.
|
||||
- `location` - Azure datacenter in which your VM will be built.
|
||||
- `temp_resource_group_name` - Name assigned to the temporary resource group created during the build. If this value is not set, a random value will be assigned. This resource group is deleted at the end of the build.
|
||||
- `private_virtual_network_with_public_ip` - This value allows you to set a `virtual_network_name` and obtain a public IP. If this value is not set and `virtual_network_name` is defined Packer is only allowed to be executed from a host on the same subnet / virtual network.
|
||||
- `virtual_network_name` - Use a pre-existing virtual network for the VM. This option enables private communication with the VM, no public IP address is used or provisioned (unless you set `private_virtual_network_with_public_ip`).
|
||||
@@ -118,6 +211,7 @@ The Packer template includes `variables` section containing user variables used
|
||||
- `capture_name_prefix` - VHD prefix. The final artifacts will be named PREFIX-osDisk.UUID and PREFIX-vmTemplate.UUID.
|
||||
|
||||
### Builder variables
|
||||
|
||||
The `builders` section contains variables for the `azure-arm` builder used in the project. Most of the builder variables are inherited from the `user variables` section, however, the variables can be overwritten to adjust image-generation performance.
|
||||
|
||||
- `vm_size` - Size of the VM used for building. This can be changed when you deploy a VM from your VHD.
|
||||
@@ -127,9 +221,11 @@ The `builders` section contains variables for the `azure-arm` builder used in th
|
||||
**Detailed Azure builders documentation can be found in [packer documentation](https://www.packer.io/docs/builders/azure).**
|
||||
|
||||
### Toolset
|
||||
|
||||
Configuration for some installed software is located in `toolset.json` files. These files define the list of Ruby, Python, Go versions, the list of PowerShell modules and VS components that will be installed to image. They can be changed if these tools are not required to reduce image generation time or image size.
|
||||
|
||||
Generated tool versions and details can be found in related projects:
|
||||
|
||||
- [Python](https://github.com/actions/python-versions/)
|
||||
- [Go](https://github.com/actions/go-versions)
|
||||
- [Node](https://github.com/actions/node-versions)
|
||||
@@ -139,24 +235,30 @@ Generated tool versions and details can be found in related projects:
|
||||
> :warning: These scripts are intended to run on a VM deployed in Azure
|
||||
|
||||
The user, created during the image generation, does not exist in the result VHD hence some configuration files related to the user's home directory need to be changed as well as the file permissions for some directories. Scripts for that are located in the `post-generation` folder in the repository:
|
||||
- Windows: https://github.com/actions/virtual-environments/tree/main/images/win/post-generation
|
||||
- Linux: https://github.com/actions/virtual-environments/tree/main/images/linux/post-generation
|
||||
|
||||
- Windows: <https://github.com/actions/runner-images/tree/main/images/win/post-generation>
|
||||
- Linux: <https://github.com/actions/runner-images/tree/main/images/linux/post-generation>
|
||||
|
||||
**Note:** The default user for Linux should have `sudo privileges`.
|
||||
|
||||
The scripts are copied to the VHD during the image generation process to the following paths:
|
||||
|
||||
- Windows: `C:\post-generation`
|
||||
- Linux: `/opt/post-generation`
|
||||
- Linux: `/opt/post-generation`
|
||||
|
||||
#### Running scripts
|
||||
|
||||
##### Ubuntu
|
||||
- Ubuntu
|
||||
|
||||
sudo su -c "find /opt/post-generation -mindepth 1 -maxdepth 1 -type f -name '*.sh' -exec bash {} \;"
|
||||
```bash
|
||||
sudo su -c "find /opt/post-generation -mindepth 1 -maxdepth 1 -type f -name '*.sh' -exec bash {} \;"
|
||||
```
|
||||
|
||||
##### Windows
|
||||
- Windows
|
||||
|
||||
Get-ChildItem C:\post-generation -Filter *.ps1 | ForEach-Object { & $_.FullName }
|
||||
```powershell
|
||||
Get-ChildItem C:\post-generation -Filter *.ps1 | ForEach-Object { & $_.FullName }
|
||||
```
|
||||
|
||||
#### Script details
|
||||
|
||||
@@ -165,13 +267,11 @@ The scripts are copied to the VHD during the image generation process to the fol
|
||||
- **cleanup-logs.sh** - removes all build process logs from the machine
|
||||
- **environment-variables.sh** - replaces `$HOME` with the default user's home directory for environmental variables related to the default user home directory
|
||||
- **homebrew-permissions.sh** - Resets homebrew repository directory by running `git reset --hard` to make the working tree clean after chmoding /home and changes the repository directory owner to the current user
|
||||
- **rust-permissions.sh** - fixes permissions for the Rust folder. Detailed issue explanation is provided in [virtual-environments/issues/572](https://github.com/actions/virtual-environments/issues/572).
|
||||
- **rust-permissions.sh** - fixes permissions for the Rust folder. Detailed issue explanation is provided in [runner-images/issues/572](https://github.com/actions/runner-images/issues/572).
|
||||
|
||||
##### Windows
|
||||
|
||||
- **Choco.ps1** - contains dummy command to cleanup orphaned packages to avoid initial delay for future choco commands
|
||||
- **Dotnet.ps1** - adds `$env:USERPROFILE\.dotnet\tools` directory to the PATH
|
||||
- **GenerateIISExpressCertificate.ps1** - generates and imports a certificate to run applications with IIS Express through HTTPS
|
||||
- **InternetExplorerConfiguration** - turns off the Internet Explorer Enhanced Security feature
|
||||
- **Msys2FirstLaunch.ps1** - initializes bash user profile in MSYS2
|
||||
- **RustJunction.ps1** - creates Rust junction points to cargo and rustup folders
|
||||
- **VSConfiguration.ps1** - performs initial Visual Studio configuration
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# Software and image guidelines
|
||||
|
||||
## Software preinstallation policy
|
||||
In general, these are the guidelines we consider when deciding what to pre-install:
|
||||
|
||||
- Tools and ecosystems that are broadly popular and widely-used will be given priority.
|
||||
- Recent versions of tools will be given priority over older versions.
|
||||
- Tools and versions that are deprecated or have reached end-of-life will not be added.
|
||||
- If a tool can be installed during the build, we will evaluate how much time is saved
|
||||
and how much space is used by having the tool pre-installed.
|
||||
- MIT, Apache, and GNU licenses are ok, anything else we'll have to check with lawyers.
|
||||
- If a tool takes much space we will evaluate space usage and provide a decision if this tool can be pre-installed.
|
||||
- If a tool requires the support of more than one version, we will consider the cost of this maintenance, how often new versions bring dangerous updates.
|
||||
|
||||
**Note:** For new tools, please, create an issue and get an approval from us to add this tool to the image before creating the pull request.
|
||||
|
||||
## Software and images support policy
|
||||
These are the guidelines we follow in software and images supporting routine:
|
||||
- Tools and versions will typically be removed 6 months after they are deprecated or have reached end-of-life.
|
||||
- We support at least 2 latest OS versions (LTS only for Ubuntu) and initiate deprecation process for the oldest one when image usage drops below 5%.
|
||||
- The images generally contain the latest versions of packages installed except for Ubuntu LTS where we rely on the Canonical-provided repositories mostly.
|
||||
- Popular tools can have several versions installed side-by-side with the following strategy:
|
||||
|
||||
| Tool name | Installation strategy |
|
||||
|-----------|-----------------------|
|
||||
| Docker images | not more than 3 latest LTS OS\tool versions. New images or new versions of current images are added using the standard tool request process |
|
||||
| Java | all LTS versions |
|
||||
| Node.js | 3 latest LTS versions |
|
||||
| Go | 3 latest minor versions |
|
||||
| Python <br/> Ruby | 5 most popular `major.minor` versions |
|
||||
| PyPy | 3 most popular `major.minor` versions |
|
||||
| .NET Core | 2 latest LTS versions and 1 latest version. For each feature version only latest patch is installed |
|
||||
| GCC <br/> GNU Fortran <br/> Clang <br/> GNU C++ | 3 latest major versions |
|
||||
| Android NDK | 1 latest non-LTS, 2 latest LTS versions |
|
||||
| Xcode | - all OS compatible versions side-by-side <br/> - for beta, GM versions - latest beta only <br/> - old patch versions are deprecated in 3 months |
|
||||
|
||||
## Software default versions update policy for tools with multiple versions installed
|
||||
In general, once a new version is installed on the image, we announce the default version update 2 weeks prior to deploying it to give time to adapt to upcoming changes. For potentially dangerous updates, we can extend the timeline up to 1 month between the announcement and deployment.
|
||||
@@ -28,7 +28,7 @@ Function CreateAzureVMFromPackerTemplate {
|
||||
The location where the Azure virtual machine will be provisioned. Example: "eastus"
|
||||
|
||||
.EXAMPLE
|
||||
CreateAzureVMFromPackerTemplate -SubscriptionId {YourSubscriptionId} -ResourceGroupName {ResourceGroupName} -TemplateFile "C:\BuildVmImages\temporaryTemplate.json" -VirtualMachineName "testvm1" -AdminUsername "shady1" -AdminPassword "SomeSecurePassword1" -AzureLocation "eastus"
|
||||
CreateAzureVMFromPackerTemplate -SubscriptionId {YourSubscriptionId} -ResourceGroupName {ResourceGroupName} -TemplateFile "C:\BuildVmImages\temporaryTemplate.json" -VirtualMachineName "testvm1" -AdminUsername "shady1" -AdminPassword "SomeSecurePassword1" -AzureLocation "eastus"
|
||||
#>
|
||||
param (
|
||||
[Parameter(Mandatory = $True)]
|
||||
@@ -63,14 +63,14 @@ Function CreateAzureVMFromPackerTemplate {
|
||||
$networkId = ($nic | ConvertFrom-Json).NewNIC.id
|
||||
|
||||
Write-Host "`nCreating a public IP address"
|
||||
($publicIp = az network public-ip create -g $ResourceGroupName -l $AzureLocation -n $publicIpName --allocation-method Static --sku Standard --version IPv4 --subscription $subscriptionId -o json)
|
||||
($publicIp = az network public-ip create -g $ResourceGroupName -l $AzureLocation -n $publicIpName --allocation-method Static --sku Basic --version IPv4 --subscription $subscriptionId -o json)
|
||||
$publicIpId = ($publicIp | ConvertFrom-Json).publicIp.id
|
||||
|
||||
Write-Host "`nAdding the public IP to the NIC"
|
||||
az network nic ip-config update -g $ResourceGroupName -n ipconfig1 --nic-name $nicName --public-ip-address $publicIpId --subscription $subscriptionId
|
||||
|
||||
Write-Host "`nCreating the VM"
|
||||
az group deployment create -g $ResourceGroupName -n $VirtualMachineName --subscription $subscriptionId --template-file $templateFilePath --parameters vmSize=$vmSize vmName=$VirtualMachineName adminUserName=$AdminUsername adminPassword=$AdminPassword networkInterfaceId=$networkId
|
||||
|
||||
Write-Host "`nCreated in $(ResourceGroupName):`n vnet $(vnetName)`n subnet $(subnetName)`n nic $(nicName)`n publicip $(publicIpName)`n vm $(VirtualMachineName)"
|
||||
az deployment group create -g $ResourceGroupName -n $VirtualMachineName --subscription $subscriptionId --template-file $templateFilePath --parameters vmSize=$vmSize vmName=$VirtualMachineName adminUserName=$AdminUsername adminPassword=$AdminPassword networkInterfaceId=$networkId
|
||||
|
||||
Write-Host "`nCreated in ${ResourceGroupName}:`n vnet ${vnetName}`n subnet ${subnetName}`n nic ${nicName}`n publicip ${publicIpName}`n vm ${VirtualMachineName}"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
enum ImageType {
|
||||
Windows2016 = 0
|
||||
Windows2019 = 1
|
||||
Windows2022 = 2
|
||||
Ubuntu1804 = 3
|
||||
Ubuntu2004 = 4
|
||||
Ubuntu2004 = 3
|
||||
Ubuntu2204 = 4
|
||||
UbuntuMinimal = 5
|
||||
}
|
||||
|
||||
Function Get-PackerTemplatePath {
|
||||
@@ -17,21 +17,21 @@ Function Get-PackerTemplatePath {
|
||||
)
|
||||
|
||||
switch ($ImageType) {
|
||||
([ImageType]::Windows2016) {
|
||||
$relativeTemplatePath = Join-Path "win" "windows2016.json"
|
||||
}
|
||||
([ImageType]::Windows2019) {
|
||||
$relativeTemplatePath = Join-Path "win" "windows2019.json"
|
||||
}
|
||||
([ImageType]::Windows2022) {
|
||||
$relativeTemplatePath = Join-Path "win" "windows2022.json"
|
||||
}
|
||||
([ImageType]::Ubuntu1804) {
|
||||
$relativeTemplatePath = Join-Path "linux" "ubuntu1804.json"
|
||||
}
|
||||
([ImageType]::Ubuntu2004) {
|
||||
$relativeTemplatePath = Join-Path "linux" "ubuntu2004.json"
|
||||
}
|
||||
([ImageType]::Ubuntu2204) {
|
||||
$relativeTemplatePath = Join-Path "linux" "ubuntu2204.pkr.hcl"
|
||||
}
|
||||
([ImageType]::UbuntuMinimal) {
|
||||
$relativeTemplatePath = Join-Path "linux" "ubuntuminimal.pkr.hcl"
|
||||
}
|
||||
default { throw "Unknown type of image" }
|
||||
}
|
||||
|
||||
@@ -58,46 +58,37 @@ Function GenerateResourcesAndImage {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
A helper function to help generate an image.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates Azure resources and kicks off a packer image generation for the selected image type.
|
||||
|
||||
.PARAMETER SubscriptionId
|
||||
The Azure subscription Id where resources will be created.
|
||||
|
||||
.PARAMETER ResourceGroupName
|
||||
The Azure resource group name where the Azure resources will be created.
|
||||
|
||||
.PARAMETER ImageGenerationRepositoryRoot
|
||||
The root path of the image generation repository source.
|
||||
|
||||
.PARAMETER ImageType
|
||||
The type of the image being generated. Valid options are: {"Windows2016", "Windows2019", "Windows2022", "Ubuntu1804", "Ubuntu2004"}.
|
||||
|
||||
The type of the image being generated. Valid options are: {"Windows2019", "Windows2022", "Ubuntu2004", "Ubuntu2204", "UbuntuMinimal"}.
|
||||
.PARAMETER AzureLocation
|
||||
The location of the resources being created in Azure. For example "East US".
|
||||
|
||||
.PARAMETER Force
|
||||
Delete the resource group if it exists without user confirmation.
|
||||
|
||||
.PARAMETER AzureClientId
|
||||
Client id needs to be provided for optional authentication via service principal. Example: "11111111-1111-1111-1111-111111111111"
|
||||
|
||||
.PARAMETER AzureClientSecret
|
||||
Client secret needs to be provided for optional authentication via service principal. Example: "11111111-1111-1111-1111-111111111111"
|
||||
|
||||
.PARAMETER AzureTenantId
|
||||
Tenant needs to be provided for optional authentication via service principal. Example: "11111111-1111-1111-1111-111111111111"
|
||||
|
||||
.PARAMETER RestrictToAgentIpAddress
|
||||
If set, access to the VM used by packer to generate the image is restricted to the public IP address this script is run from.
|
||||
This parameter cannot be used in combination with the virtual_network_name packer parameter.
|
||||
|
||||
.PARAMETER AllowBlobPublicAccess
|
||||
The Azure storage account will be created with this option.
|
||||
|
||||
.PARAMETER EnableHttpsTrafficOnly
|
||||
The Azure storage account will be created with this option.
|
||||
.PARAMETER OnError
|
||||
Specify how packer handles an error during image creation.
|
||||
.EXAMPLE
|
||||
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "shsamytest1" -ImageGenerationRepositoryRoot "C:\virtual-environments" -ImageType Ubuntu1804 -AzureLocation "East US"
|
||||
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "shsamytest1" -ImageGenerationRepositoryRoot "C:\runner-images" -ImageType Ubuntu2004 -AzureLocation "East US"
|
||||
#>
|
||||
param (
|
||||
[Parameter(Mandatory = $True)]
|
||||
@@ -125,147 +116,207 @@ Function GenerateResourcesAndImage {
|
||||
[Parameter(Mandatory = $False)]
|
||||
[bool] $AllowBlobPublicAccess = $False,
|
||||
[Parameter(Mandatory = $False)]
|
||||
[bool] $EnableHttpsTrafficOnly = $False
|
||||
[bool] $EnableHttpsTrafficOnly = $False,
|
||||
[Parameter(Mandatory = $False)]
|
||||
[ValidateSet("abort","ask","cleanup","run-cleanup-provisioner")]
|
||||
[string] $OnError = "ask",
|
||||
[Parameter(Mandatory = $False)]
|
||||
[hashtable] $Tags
|
||||
)
|
||||
|
||||
$builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType
|
||||
$ServicePrincipalClientSecret = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
$InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
|
||||
if ([string]::IsNullOrEmpty($AzureClientId))
|
||||
{
|
||||
Connect-AzAccount
|
||||
} else {
|
||||
$AzSecureSecret = ConvertTo-SecureString $AzureClientSecret -AsPlainText -Force
|
||||
$AzureAppCred = New-Object System.Management.Automation.PSCredential($AzureClientId, $AzSecureSecret)
|
||||
Connect-AzAccount -ServicePrincipal -Credential $AzureAppCred -Tenant $AzureTenantId
|
||||
}
|
||||
Set-AzContext -SubscriptionId $SubscriptionId
|
||||
|
||||
$alreadyExists = $true;
|
||||
try {
|
||||
Get-AzResourceGroup -Name $ResourceGroupName
|
||||
Write-Verbose "Resource group was found, will delete and recreate it."
|
||||
$builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType
|
||||
$ServicePrincipalClientSecret = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
$InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
|
||||
if ([string]::IsNullOrEmpty($AzureClientId))
|
||||
{
|
||||
Connect-AzAccount
|
||||
} else {
|
||||
$AzSecureSecret = ConvertTo-SecureString $AzureClientSecret -AsPlainText -Force
|
||||
$AzureAppCred = New-Object System.Management.Automation.PSCredential($AzureClientId, $AzSecureSecret)
|
||||
Connect-AzAccount -ServicePrincipal -Credential $AzureAppCred -Tenant $AzureTenantId
|
||||
}
|
||||
Set-AzContext -SubscriptionId $SubscriptionId
|
||||
|
||||
$alreadyExists = $true;
|
||||
try {
|
||||
Get-AzResourceGroup -Name $ResourceGroupName
|
||||
Write-Verbose "Resource group was found, will delete and recreate it."
|
||||
}
|
||||
catch {
|
||||
Write-Verbose "Resource group was not found, will create it."
|
||||
$alreadyExists = $false;
|
||||
}
|
||||
|
||||
if ($alreadyExists) {
|
||||
if($Force -eq $true) {
|
||||
# Cleanup the resource group if it already exitsted before
|
||||
Remove-AzResourceGroup -Name $ResourceGroupName -Force
|
||||
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation -Tag $tags
|
||||
|
||||
} else {
|
||||
$title = "Delete Resource Group"
|
||||
$message = "The resource group you specified already exists. Do you want to clean it up?"
|
||||
|
||||
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
|
||||
"Delete the resource group including all resources."
|
||||
|
||||
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
|
||||
"Keep the resource group and continue."
|
||||
|
||||
$stop = New-Object System.Management.Automation.Host.ChoiceDescription "&Stop", `
|
||||
"Stop the current action."
|
||||
|
||||
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $stop)
|
||||
$result = $host.ui.PromptForChoice($title, $message, $options, 0)
|
||||
|
||||
switch ($result)
|
||||
{
|
||||
0 { Remove-AzResourceGroup -Name $ResourceGroupName -Force; New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation -Tag $tags }
|
||||
1 { <# Do nothing #> }
|
||||
2 { exit }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation -Tag $tags
|
||||
}
|
||||
|
||||
# This script should follow the recommended naming conventions for azure resources
|
||||
$storageAccountName = if($ResourceGroupName.EndsWith("-rg")) {
|
||||
$ResourceGroupName.Substring(0, $ResourceGroupName.Length -3)
|
||||
} else { $ResourceGroupName }
|
||||
|
||||
# Resource group names may contain special characters, that are not allowed in the storage account name
|
||||
$storageAccountName = $storageAccountName.Replace("-", "").Replace("_", "").Replace("(", "").Replace(")", "").ToLower()
|
||||
$storageAccountName += "001"
|
||||
|
||||
|
||||
# Storage Account Name can only be 24 characters long
|
||||
if ($storageAccountName.Length -gt 24){
|
||||
$storageAccountName = $storageAccountName.Substring(0, 24)
|
||||
}
|
||||
|
||||
if ($tags) {
|
||||
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS" -AllowBlobPublicAccess $AllowBlobPublicAccess -EnableHttpsTrafficOnly $EnableHttpsTrafficOnly -Tag $tags
|
||||
} else {
|
||||
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS" -AllowBlobPublicAccess $AllowBlobPublicAccess -EnableHttpsTrafficOnly $EnableHttpsTrafficOnly
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($AzureClientId)) {
|
||||
# Interactive authentication: A service principal is created during runtime.
|
||||
$spDisplayName = [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
$startDate = Get-Date
|
||||
$endDate = $startDate.AddYears(1)
|
||||
|
||||
if ('Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential' -as [type]) {
|
||||
$credentials = [Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential]@{
|
||||
StartDate = $startDate
|
||||
EndDate = $endDate
|
||||
Password = $ServicePrincipalClientSecret
|
||||
}
|
||||
$sp = New-AzADServicePrincipal -DisplayName $spDisplayName -PasswordCredential $credentials
|
||||
$spClientId = $sp.ApplicationId
|
||||
$azRoleParam = @{
|
||||
RoleDefinitionName = "Contributor"
|
||||
ServicePrincipalName = $spClientId
|
||||
}
|
||||
}
|
||||
|
||||
if ('Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential' -as [type]) {
|
||||
$credentials = [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential]@{
|
||||
StartDateTime = $startDate
|
||||
EndDateTime = $endDate
|
||||
}
|
||||
$sp = New-AzADServicePrincipal -DisplayName $spDisplayName
|
||||
$appCred = New-AzADAppCredential -ApplicationId $sp.AppId -PasswordCredentials $credentials
|
||||
$spClientId = $sp.AppId
|
||||
$azRoleParam = @{
|
||||
RoleDefinitionName = "Contributor"
|
||||
PrincipalId = $sp.Id
|
||||
}
|
||||
$ServicePrincipalClientSecret = $appCred.SecretText
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
|
||||
New-AzRoleAssignment @azRoleParam
|
||||
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
|
||||
$sub = Get-AzSubscription -SubscriptionId $SubscriptionId
|
||||
$tenantId = $sub.TenantId
|
||||
|
||||
# Remove ADPrincipal after the script completed
|
||||
$isCleanupADPrincipal = $true
|
||||
} else {
|
||||
# Parametrized Authentication via given service principal: The service principal with the data provided via the command line
|
||||
# is used for all authentication purposes.
|
||||
$spClientId = $AzureClientId
|
||||
$credentials = $AzureAppCred
|
||||
$ServicePrincipalClientSecret = $AzureClientSecret
|
||||
$tenantId = $AzureTenantId
|
||||
}
|
||||
|
||||
Get-LatestCommit -ErrorAction SilentlyContinue
|
||||
|
||||
$packerBinary = Get-Command "packer"
|
||||
if (-not ($packerBinary)) {
|
||||
throw "'packer' binary is not found on PATH"
|
||||
}
|
||||
|
||||
if ($RestrictToAgentIpAddress) {
|
||||
$AgentIp = (Invoke-RestMethod http://ipinfo.io/json).ip
|
||||
Write-Host "Restricting access to packer generated VM to agent IP Address: $AgentIp"
|
||||
}
|
||||
|
||||
if ($builderScriptPath.Contains("pkr.hcl")) {
|
||||
if ($AgentIp) {
|
||||
$AgentIp = '[ \"{0}\" ]' -f $AgentIp
|
||||
} else {
|
||||
$AgentIp = "[]"
|
||||
}
|
||||
if (-not $Tags) {
|
||||
$Tags = @{}
|
||||
}
|
||||
}
|
||||
|
||||
if ($builderScriptPath.Contains(".json")) {
|
||||
if ($Tags) {
|
||||
$builderScriptPath_temp = $builderScriptPath.Replace(".json", "-temp.json")
|
||||
$packer_script = Get-Content -Path $builderScriptPath | ConvertFrom-Json
|
||||
$packer_script.builders | Add-Member -Name "azure_tags" -Value $Tags -MemberType NoteProperty
|
||||
$packer_script | ConvertTo-Json -Depth 3 | Out-File -Encoding Ascii $builderScriptPath_temp
|
||||
$builderScriptPath = $builderScriptPath_temp
|
||||
}
|
||||
}
|
||||
|
||||
& $packerBinary build -on-error="$($OnError)" `
|
||||
-var "client_id=$($spClientId)" `
|
||||
-var "client_secret=$($ServicePrincipalClientSecret)" `
|
||||
-var "subscription_id=$($SubscriptionId)" `
|
||||
-var "tenant_id=$($tenantId)" `
|
||||
-var "location=$($AzureLocation)" `
|
||||
-var "resource_group=$($ResourceGroupName)" `
|
||||
-var "storage_account=$($storageAccountName)" `
|
||||
-var "install_password=$($InstallPassword)" `
|
||||
-var "allowed_inbound_ip_addresses=$($AgentIp)" `
|
||||
-var "azure_tags=$($Tags | ConvertTo-Json -Compress)" `
|
||||
$builderScriptPath
|
||||
}
|
||||
catch {
|
||||
Write-Verbose "Resource group was not found, will create it."
|
||||
$alreadyExists = $false;
|
||||
Write-Error $_
|
||||
}
|
||||
finally {
|
||||
# Remove ADServicePrincipal and ADApplication
|
||||
if ($isCleanupADPrincipal) {
|
||||
Write-Host "`nRemoving ${spDisplayName}/${spClientId}:"
|
||||
if (Get-AzADServicePrincipal -DisplayName $spDisplayName) {
|
||||
Write-Host " [+] ADServicePrincipal"
|
||||
Remove-AzADServicePrincipal -DisplayName $spDisplayName -Confirm:$false
|
||||
}
|
||||
|
||||
if ($alreadyExists) {
|
||||
if($Force -eq $true) {
|
||||
# Cleanup the resource group if it already exitsted before
|
||||
Remove-AzResourceGroup -Name $ResourceGroupName -Force
|
||||
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
|
||||
} else {
|
||||
$title = "Delete Resource Group"
|
||||
$message = "The resource group you specified already exists. Do you want to clean it up?"
|
||||
|
||||
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
|
||||
"Delete the resource group including all resources."
|
||||
|
||||
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
|
||||
"Keep the resource group and continue."
|
||||
|
||||
$stop = New-Object System.Management.Automation.Host.ChoiceDescription "&Stop", `
|
||||
"Stop the current action."
|
||||
|
||||
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $stop)
|
||||
$result = $host.ui.PromptForChoice($title, $message, $options, 0)
|
||||
|
||||
switch ($result)
|
||||
{
|
||||
0 { Remove-AzResourceGroup -Name $ResourceGroupName -Force; New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation }
|
||||
1 { <# Do nothing #> }
|
||||
2 { exit }
|
||||
if (Get-AzADApplication -DisplayName $spDisplayName) {
|
||||
Write-Host " [+] ADApplication"
|
||||
Remove-AzADApplication -DisplayName $spDisplayName -Confirm:$false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
|
||||
}
|
||||
|
||||
# This script should follow the recommended naming conventions for azure resources
|
||||
$storageAccountName = if($ResourceGroupName.EndsWith("-rg")) {
|
||||
$ResourceGroupName.Substring(0, $ResourceGroupName.Length -3)
|
||||
} else { $ResourceGroupName }
|
||||
|
||||
# Resource group names may contain special characters, that are not allowed in the storage account name
|
||||
$storageAccountName = $storageAccountName.Replace("-", "").Replace("_", "").Replace("(", "").Replace(")", "").ToLower()
|
||||
$storageAccountName += "001"
|
||||
|
||||
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS" -AllowBlobPublicAccess $AllowBlobPublicAccess -EnableHttpsTrafficOnly $EnableHttpsTrafficOnly
|
||||
|
||||
if ([string]::IsNullOrEmpty($AzureClientId)) {
|
||||
# Interactive authentication: A service principal is created during runtime.
|
||||
$spDisplayName = [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
$startDate = Get-Date
|
||||
$endDate = $startDate.AddYears(1)
|
||||
|
||||
if ('Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential' -as [type]) {
|
||||
$credentials = [Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential]@{
|
||||
StartDate = $startDate
|
||||
EndDate = $endDate
|
||||
Password = $ServicePrincipalClientSecret
|
||||
}
|
||||
$sp = New-AzADServicePrincipal -DisplayName $spDisplayName -PasswordCredential $credentials
|
||||
$spClientId = $sp.ApplicationId
|
||||
$azRoleParam = @{
|
||||
RoleDefinitionName = "Contributor"
|
||||
ServicePrincipalName = $spClientId
|
||||
}
|
||||
}
|
||||
|
||||
if ('Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential' -as [type]) {
|
||||
$credentials = [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential]@{
|
||||
StartDateTime = $startDate
|
||||
EndDateTime = $endDate
|
||||
}
|
||||
$sp = New-AzADServicePrincipal -DisplayName $spDisplayName
|
||||
$appCred = New-AzADAppCredential -ApplicationId $sp.AppId -PasswordCredentials $credentials
|
||||
$spClientId = $sp.AppId
|
||||
$azRoleParam = @{
|
||||
RoleDefinitionName = "Contributor"
|
||||
PrincipalId = $sp.Id
|
||||
}
|
||||
$ServicePrincipalClientSecret = $appCred.SecretText
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
|
||||
New-AzRoleAssignment @azRoleParam
|
||||
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
|
||||
$sub = Get-AzSubscription -SubscriptionId $SubscriptionId
|
||||
$tenantId = $sub.TenantId
|
||||
# "", "Note this variable-setting script for running Packer with these Azure resources in the future:", "==============================================================================================", "`$spClientId = `"$spClientId`"", "`$ServicePrincipalClientSecret = `"$ServicePrincipalClientSecret`"", "`$SubscriptionId = `"$SubscriptionId`"", "`$tenantId = `"$tenantId`"", "`$spObjectId = `"$spObjectId`"", "`$AzureLocation = `"$AzureLocation`"", "`$ResourceGroupName = `"$ResourceGroupName`"", "`$storageAccountName = `"$storageAccountName`"", "`$install_password = `"$install_password`"", ""
|
||||
} else {
|
||||
# Parametrized Authentication via given service principal: The service principal with the data provided via the command line
|
||||
# is used for all authentication purposes.
|
||||
$spClientId = $AzureClientId
|
||||
$credentials = $AzureAppCred
|
||||
$ServicePrincipalClientSecret = $AzureClientSecret
|
||||
$tenantId = $AzureTenantId
|
||||
}
|
||||
|
||||
Get-LatestCommit -ErrorAction SilentlyContinue
|
||||
|
||||
$packerBinary = Get-Command "packer"
|
||||
if (-not ($packerBinary)) {
|
||||
throw "'packer' binary is not found on PATH"
|
||||
}
|
||||
|
||||
if($RestrictToAgentIpAddress -eq $true) {
|
||||
$AgentIp = (Invoke-RestMethod http://ipinfo.io/json).ip
|
||||
Write-Host "Restricting access to packer generated VM to agent IP Address: $AgentIp"
|
||||
}
|
||||
|
||||
& $packerBinary build -on-error=ask `
|
||||
-var "client_id=$($spClientId)" `
|
||||
-var "client_secret=$($ServicePrincipalClientSecret)" `
|
||||
-var "subscription_id=$($SubscriptionId)" `
|
||||
-var "tenant_id=$($tenantId)" `
|
||||
-var "location=$($AzureLocation)" `
|
||||
-var "resource_group=$($ResourceGroupName)" `
|
||||
-var "storage_account=$($storageAccountName)" `
|
||||
-var "install_password=$($InstallPassword)" `
|
||||
-var "allowed_inbound_ip_addresses=$($AgentIp)" `
|
||||
$builderScriptPath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using module ./SoftwareReport.psm1
|
||||
using module ./SoftwareReport.DifferenceCalculator.psm1
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Calculates the difference between two software reports and saves it to a file.
|
||||
.PARAMETER PreviousJsonReportPath
|
||||
Path to the previous software report.
|
||||
.PARAMETER CurrentJsonReportPath
|
||||
Path to the current software report.
|
||||
.PARAMETER OutputFile
|
||||
Path to the file where the difference will be saved.
|
||||
.PARAMETER ReleaseBranchName
|
||||
Name of the release branch to build image docs URL.
|
||||
.PARAMETER ReadmePath
|
||||
Path to the README file in repository to build image docs URL.
|
||||
#>
|
||||
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $PreviousJsonReportPath,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $CurrentJsonReportPath,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $OutputFile,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string] $ReleaseBranchName,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string] $ReadmePath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$global:ErrorView = "NormalView"
|
||||
|
||||
function Read-SoftwareReport {
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $JsonReportPath
|
||||
)
|
||||
|
||||
if (-not (Test-Path $JsonReportPath)) {
|
||||
throw "File '$JsonReportPath' does not exist"
|
||||
}
|
||||
|
||||
$jsonReport = Get-Content -Path $JsonReportPath -Raw
|
||||
$report = [SoftwareReport]::FromJson($jsonReport)
|
||||
return $report
|
||||
}
|
||||
|
||||
$previousReport = Read-SoftwareReport -JsonReportPath $PreviousJsonReportPath
|
||||
$currentReport = Read-SoftwareReport -JsonReportPath $CurrentJsonReportPath
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($previousReport, $currentReport)
|
||||
$comparer.CompareReports()
|
||||
$diff = $comparer.GetMarkdownReport()
|
||||
|
||||
if ($ReleaseBranchName -and $ReadmePath) {
|
||||
# https://github.com/actions/runner-images/blob/releases/macOS-12/20221215/images/macos/macos-12-Readme.md
|
||||
$ImageDocsUrl = "https://github.com/actions/runner-images/blob/${ReleaseBranchName}/${ReadmePath}"
|
||||
$diff += "`n`n`nFor comprehensive list of software installed on this image please click [here]($ImageDocsUrl)."
|
||||
}
|
||||
|
||||
$parentDirectory = Split-Path $OutputFile -Parent
|
||||
if (-not (Test-Path $parentDirectory)) { New-Item -Path $parentDirectory -ItemType Directory | Out-Null }
|
||||
|
||||
$diff | Out-File -Path $OutputFile -Encoding utf8NoBOM
|
||||
@@ -0,0 +1,56 @@
|
||||
############################
|
||||
### Abstract base nodes ####
|
||||
############################
|
||||
|
||||
# Abstract base class for all nodes
|
||||
class BaseNode {
|
||||
[Boolean] ShouldBeIncludedToDiff() {
|
||||
return $false
|
||||
}
|
||||
|
||||
[String] ToMarkdown() {
|
||||
return $this.ToMarkdown(1)
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
throw "Abtract method 'ToMarkdown(level)' is not implemented for '$($this.GetType().Name)'"
|
||||
}
|
||||
|
||||
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
|
||||
throw "Abtract method 'IsSimilarTo' is not implemented for '$($this.GetType().Name)'"
|
||||
}
|
||||
|
||||
[Boolean] IsIdenticalTo([BaseNode] $OtherNode) {
|
||||
throw "Abtract method 'IsIdenticalTo' is not implemented for '$($this.GetType().Name)'"
|
||||
}
|
||||
}
|
||||
|
||||
# Abstract base class for all nodes that describe a tool and should be rendered inside diff table
|
||||
class BaseToolNode: BaseNode {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String] $ToolName
|
||||
|
||||
BaseToolNode([String] $ToolName) {
|
||||
$this.ToolName = $ToolName
|
||||
}
|
||||
|
||||
[Boolean] ShouldBeIncludedToDiff() {
|
||||
return $true
|
||||
}
|
||||
|
||||
[String] GetValue() {
|
||||
throw "Abtract method 'GetValue' is not implemented for '$($this.GetType().Name)'"
|
||||
}
|
||||
|
||||
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
|
||||
if ($this.GetType() -ne $OtherNode.GetType()) {
|
||||
return $false
|
||||
}
|
||||
|
||||
return $this.ToolName -eq $OtherNode.ToolName
|
||||
}
|
||||
|
||||
[Boolean] IsIdenticalTo([BaseNode] $OtherNode) {
|
||||
return $this.IsSimilarTo($OtherNode) -and ($this.GetValue() -eq $OtherNode.GetValue())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using module ./SoftwareReport.psm1
|
||||
using module ./SoftwareReport.BaseNodes.psm1
|
||||
using module ./SoftwareReport.Nodes.psm1
|
||||
using module ./SoftwareReport.DifferenceRender.psm1
|
||||
|
||||
class SoftwareReportDifferenceCalculator {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
hidden [SoftwareReport] $PreviousReport
|
||||
[ValidateNotNullOrEmpty()]
|
||||
hidden [SoftwareReport] $CurrentReport
|
||||
|
||||
hidden [Collections.Generic.List[ReportDifferenceItem]] $AddedItems
|
||||
hidden [Collections.Generic.List[ReportDifferenceItem]] $ChangedItems
|
||||
hidden [Collections.Generic.List[ReportDifferenceItem]] $DeletedItems
|
||||
|
||||
SoftwareReportDifferenceCalculator([SoftwareReport] $PreviousReport, [SoftwareReport] $CurrentReport) {
|
||||
$this.PreviousReport = $PreviousReport
|
||||
$this.CurrentReport = $CurrentReport
|
||||
}
|
||||
|
||||
[void] CompareReports() {
|
||||
$this.AddedItems = @()
|
||||
$this.ChangedItems = @()
|
||||
$this.DeletedItems = @()
|
||||
|
||||
$this.CompareInternal($this.PreviousReport.Root, $this.CurrentReport.Root, @())
|
||||
}
|
||||
|
||||
[String] GetMarkdownReport() {
|
||||
$reporter = [SoftwareReportDifferenceRender]::new()
|
||||
$report = $reporter.GenerateMarkdownReport($this.CurrentReport, $this.PreviousReport, $this.AddedItems, $this.ChangedItems, $this.DeletedItems)
|
||||
return $report
|
||||
}
|
||||
|
||||
hidden [void] CompareInternal([HeaderNode] $previousReportPointer, [HeaderNode] $currentReportPointer, [String[]] $Headers) {
|
||||
$currentReportPointer.Children ?? @() | Where-Object { $_.ShouldBeIncludedToDiff() -and $this.FilterExcludedNodes($_) } | ForEach-Object {
|
||||
$currentReportNode = $_
|
||||
$sameNodeInPreviousReport = $previousReportPointer ? $previousReportPointer.FindSimilarChildNode($currentReportNode) : $null
|
||||
|
||||
if ($currentReportNode -is [HeaderNode]) {
|
||||
# Compare HeaderNode recursively
|
||||
$this.CompareInternal($sameNodeInPreviousReport, $currentReportNode, $Headers + $currentReportNode.Title)
|
||||
} else {
|
||||
if ($sameNodeInPreviousReport -and ($currentReportNode.IsIdenticalTo($sameNodeInPreviousReport))) {
|
||||
# Nodes are identical, nothing changed, just ignore it
|
||||
} elseif ($sameNodeInPreviousReport) {
|
||||
# Nodes are equal but not identical, something was changed
|
||||
if ($currentReportNode -is [TableNode]) {
|
||||
$this.CompareSimilarTableNodes($sameNodeInPreviousReport, $currentReportNode, $Headers)
|
||||
} elseif ($currentReportNode -is [ToolVersionsListNode]) {
|
||||
$this.CompareSimilarToolVersionsListNodes($sameNodeInPreviousReport, $currentReportNode, $Headers)
|
||||
} else {
|
||||
$this.ChangedItems.Add([ReportDifferenceItem]::new($sameNodeInPreviousReport, $currentReportNode, $Headers))
|
||||
}
|
||||
} else {
|
||||
# Node was not found in previous report, new node was added
|
||||
$this.AddedItems.Add([ReportDifferenceItem]::new($null, $currentReportNode, $Headers))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Detecting nodes that were removed
|
||||
$previousReportPointer.Children ?? @() | Where-Object { $_.ShouldBeIncludedToDiff() -and $this.FilterExcludedNodes($_) } | ForEach-Object {
|
||||
$previousReportNode = $_
|
||||
$sameNodeInCurrentReport = $currentReportPointer ? $currentReportPointer.FindSimilarChildNode($previousReportNode) : $null
|
||||
|
||||
if (-not $sameNodeInCurrentReport) {
|
||||
if ($previousReportNode -is [HeaderNode]) {
|
||||
# Compare removed HeaderNode recursively
|
||||
$this.CompareInternal($previousReportNode, $null, $Headers + $previousReportNode.Title)
|
||||
} else {
|
||||
# Node was not found in current report, node was removed
|
||||
$this.DeletedItems.Add([ReportDifferenceItem]::new($previousReportNode, $null, $Headers))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hidden [void] CompareSimilarTableNodes([TableNode] $PreviousReportNode, [TableNode] $CurrentReportNode, [String[]] $Headers) {
|
||||
$addedRows = $CurrentReportNode.Rows | Where-Object { $_ -notin $PreviousReportNode.Rows }
|
||||
$deletedRows = $PreviousReportNode.Rows | Where-Object { $_ -notin $CurrentReportNode.Rows }
|
||||
|
||||
if (($addedRows.Count -eq 0) -and ($deletedRows.Count -eq 0)) {
|
||||
# Unexpected state: TableNodes are identical
|
||||
return
|
||||
}
|
||||
|
||||
if ($PreviousReportNode.Headers -ne $CurrentReportNode.Headers) {
|
||||
# If headers are changed and rows are changed at the same time, we should track it as removing table and adding new one
|
||||
$this.DeletedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $null, $Headers))
|
||||
$this.AddedItems.Add([ReportDifferenceItem]::new($null, $CurrentReportNode, $Headers))
|
||||
} elseif (($addedRows.Count -gt 0) -and ($deletedRows.Count -eq 0)) {
|
||||
# If new rows were added and no rows were deleted, then it is AddedItem
|
||||
$this.AddedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
|
||||
} elseif (($deletedRows.Count -gt 0) -and ($addedRows.Count -eq 0)) {
|
||||
# If no rows were added and some rows were deleted, then it is DeletedItem
|
||||
$this.DeletedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
|
||||
} else {
|
||||
# If some rows were added and some rows were removed, then it is UpdatedItem
|
||||
$this.ChangedItems.Add([ReportDifferenceItem]::new($PreviousReportNode, $CurrentReportNode, $Headers))
|
||||
}
|
||||
}
|
||||
|
||||
hidden [void] CompareSimilarToolVersionsListNodes([ToolVersionsListNode] $PreviousReportNode, [ToolVersionsListNode] $CurrentReportNode, [String[]] $Headers) {
|
||||
$previousReportMajorVersions = $PreviousReportNode.Versions | ForEach-Object { $PreviousReportNode.ExtractMajorVersion($_) }
|
||||
$currentReportMajorVersion = $CurrentReportNode.Versions | ForEach-Object { $CurrentReportNode.ExtractMajorVersion($_) }
|
||||
|
||||
$addedVersions = $CurrentReportNode.Versions | Where-Object { $CurrentReportNode.ExtractMajorVersion($_) -notin $previousReportMajorVersions }
|
||||
$deletedVersions = $PreviousReportNode.Versions | Where-Object { $PreviousReportNode.ExtractMajorVersion($_) -notin $currentReportMajorVersion }
|
||||
$changedPreviousVersions = $PreviousReportNode.Versions | Where-Object { ($PreviousReportNode.ExtractMajorVersion($_) -in $currentReportMajorVersion) -and ($_ -notin $CurrentReportNode.Versions) }
|
||||
$changedCurrentVersions = $CurrentReportNode.Versions | Where-Object { ($CurrentReportNode.ExtractMajorVersion($_) -in $previousReportMajorVersions) -and ($_ -notin $PreviousReportNode.Versions) }
|
||||
|
||||
if ($addedVersions.Count -gt 0) {
|
||||
$this.AddedItems.Add([ReportDifferenceItem]::new($null, [ToolVersionsListNode]::new($CurrentReportNode.ToolName, $addedVersions, $CurrentReportNode.MajorVersionRegex, "List"), $Headers))
|
||||
}
|
||||
|
||||
if ($deletedVersions.Count -gt 0) {
|
||||
$this.DeletedItems.Add([ReportDifferenceItem]::new([ToolVersionsListNode]::new($PreviousReportNode.ToolName, $deletedVersions, $PreviousReportNode.MajorVersionRegex, "List"), $null, $Headers))
|
||||
}
|
||||
|
||||
$previousChangedNode = ($changedPreviousVersions.Count -gt 0) ? [ToolVersionsListNode]::new($PreviousReportNode.ToolName, $changedPreviousVersions, $PreviousReportNode.MajorVersionRegex, "List") : $null
|
||||
$currentChangedNode = ($changedCurrentVersions.Count -gt 0) ? [ToolVersionsListNode]::new($CurrentReportNode.ToolName, $changedCurrentVersions, $CurrentReportNode.MajorVersionRegex, "List") : $null
|
||||
if ($previousChangedNode -and $currentChangedNode) {
|
||||
$this.ChangedItems.Add([ReportDifferenceItem]::new($previousChangedNode, $currentChangedNode, $Headers))
|
||||
}
|
||||
}
|
||||
|
||||
hidden [Boolean] FilterExcludedNodes([BaseNode] $Node) {
|
||||
# We shouldn't show "Image Version" diff because it is already shown in report header
|
||||
if (($Node -is [ToolVersionNode]) -and ($Node.ToolName -eq "Image Version:")) {
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
using module ./SoftwareReport.psm1
|
||||
using module ./SoftwareReport.BaseNodes.psm1
|
||||
using module ./SoftwareReport.Nodes.psm1
|
||||
|
||||
class SoftwareReportDifferenceRender {
|
||||
[String] GenerateMarkdownReport([SoftwareReport] $CurrentReport, [SoftwareReport] $PreviousReport, [ReportDifferenceItem[]] $AddedItems, [ReportDifferenceItem[]] $ChangedItems, [ReportDifferenceItem[]] $DeletedItems) {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
$rootNode = $CurrentReport.Root
|
||||
$imageVersion = $CurrentReport.GetImageVersion()
|
||||
$previousImageVersion = $PreviousReport.GetImageVersion()
|
||||
|
||||
#############################
|
||||
### Render report header ####
|
||||
#############################
|
||||
|
||||
$sb.AppendLine("# :desktop_computer: Actions Runner Image: $($rootNode.Title)")
|
||||
|
||||
# ToolVersionNodes on root level contains main image description so just copy-paste them to final report
|
||||
$rootNode.Children | Where-Object { $_ -is [ToolVersionNode] } | ForEach-Object {
|
||||
$sb.AppendLine($_.ToMarkdown())
|
||||
}
|
||||
$sb.AppendLine()
|
||||
|
||||
$sb.AppendLine("## :mega: What's changed?").AppendLine()
|
||||
|
||||
###########################
|
||||
### Render added items ####
|
||||
###########################
|
||||
|
||||
[ReportDifferenceItem[]] $addedItemsBaseTools = $AddedItems | Where-Object { $_.IsBaseToolNode() }
|
||||
[ReportDifferenceItem[]] $addedItemsTables = $AddedItems | Where-Object { $_.IsTableNode() }
|
||||
if ($addedItemsBaseTools.Count + $addedItemsTables.Count -gt 0) {
|
||||
$sb.AppendLine("### Added :heavy_plus_sign:").AppendLine()
|
||||
}
|
||||
if ($addedItemsBaseTools.Count -gt 0) {
|
||||
$tableItems = $addedItemsBaseTools | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
"Category" = $this.RenderCategory($_.Headers, $true);
|
||||
"Tool name" = $this.RenderToolName($_.CurrentReportNode.ToolName);
|
||||
"Current ($imageVersion)" = $_.CurrentReportNode.GetValue();
|
||||
}
|
||||
}
|
||||
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
|
||||
}
|
||||
if ($addedItemsTables.Count -gt 0) {
|
||||
$addedItemsTables | ForEach-Object {
|
||||
$sb.AppendLine($this.RenderTableNodesDiff($_))
|
||||
}
|
||||
}
|
||||
|
||||
#############################
|
||||
### Render deleted items ####
|
||||
#############################
|
||||
|
||||
[ReportDifferenceItem[]] $deletedItemsBaseTools = $DeletedItems | Where-Object { $_.IsBaseToolNode() }
|
||||
[ReportDifferenceItem[]] $deletedItemsTables = $DeletedItems | Where-Object { $_.IsTableNode() }
|
||||
if ($deletedItemsBaseTools.Count + $deletedItemsTables.Count -gt 0) {
|
||||
$sb.AppendLine("### Deleted :heavy_minus_sign:").AppendLine()
|
||||
}
|
||||
if ($deletedItemsBaseTools.Count -gt 0) {
|
||||
$tableItems = $deletedItemsBaseTools | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
"Category" = $this.RenderCategory($_.Headers, $true);
|
||||
"Tool name" = $this.RenderToolName($_.PreviousReportNode.ToolName);
|
||||
"Previous ($previousImageVersion)" = $_.PreviousReportNode.GetValue();
|
||||
}
|
||||
}
|
||||
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
|
||||
}
|
||||
if ($deletedItemsTables.Count -gt 0) {
|
||||
$deletedItemsTables | ForEach-Object {
|
||||
$sb.AppendLine($this.RenderTableNodesDiff($_))
|
||||
}
|
||||
}
|
||||
|
||||
#############################
|
||||
### Render updated items ####
|
||||
#############################
|
||||
|
||||
[ReportDifferenceItem[]] $changedItemsBaseTools = $ChangedItems | Where-Object { $_.IsBaseToolNode() }
|
||||
[ReportDifferenceItem[]] $changedItemsTables = $ChangedItems | Where-Object { $_.IsTableNode() }
|
||||
if ($changedItemsBaseTools.Count + $changedItemsTables.Count -gt 0) {
|
||||
$sb.AppendLine("### Updated").AppendLine()
|
||||
}
|
||||
if ($changedItemsBaseTools.Count -gt 0) {
|
||||
$tableItems = $changedItemsBaseTools | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
"Category" = $this.RenderCategory($_.Headers, $true);
|
||||
"Tool name" = $this.RenderToolName($_.CurrentReportNode.ToolName);
|
||||
"Previous ($previousImageVersion)" = $_.PreviousReportNode.GetValue();
|
||||
"Current ($imageVersion)" = $_.CurrentReportNode.GetValue();
|
||||
}
|
||||
}
|
||||
$sb.AppendLine($this.RenderHtmlTable($tableItems, "Category"))
|
||||
}
|
||||
if ($changedItemsTables.Count -gt 0) {
|
||||
$changedItemsTables | ForEach-Object {
|
||||
$sb.AppendLine($this.RenderTableNodesDiff($_))
|
||||
}
|
||||
}
|
||||
|
||||
return $sb.ToString()
|
||||
}
|
||||
|
||||
[String] RenderHtmlTable([PSCustomObject[]] $Table, [String] $RowSpanColumnName) {
|
||||
$headers = $Table[0].PSObject.Properties.Name
|
||||
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
$sb.AppendLine("<table>")
|
||||
$sb.AppendLine(" <thead>")
|
||||
$headers | ForEach-Object {
|
||||
$sb.AppendLine(" <th>$_</th>")
|
||||
}
|
||||
$sb.AppendLine(" </thead>")
|
||||
$sb.AppendLine(" <tbody>")
|
||||
|
||||
$tableRowSpans = $this.CalculateHtmlTableRowSpan($Table, $RowSpanColumnName)
|
||||
for ($rowIndex = 0; $rowIndex -lt $Table.Count; $rowIndex++) {
|
||||
$row = $Table[$rowIndex]
|
||||
|
||||
$sb.AppendLine(" <tr>")
|
||||
$headers | ForEach-Object {
|
||||
if ($_ -eq $RowSpanColumnName) {
|
||||
if ($tableRowSpans[$rowIndex] -gt 0) {
|
||||
$sb.AppendLine(" <td rowspan=`"$($tableRowSpans[$rowIndex])`">$($row.$_)</td>")
|
||||
} else {
|
||||
# Skip rendering this cell at all
|
||||
}
|
||||
} else {
|
||||
$sb.AppendLine(" <td>$($row.$_)</td>")
|
||||
}
|
||||
}
|
||||
$sb.AppendLine(" </tr>")
|
||||
}
|
||||
$sb.AppendLine(" </tbody>")
|
||||
$sb.AppendLine("</table>")
|
||||
|
||||
return $sb.ToString()
|
||||
}
|
||||
|
||||
[int[]] CalculateHtmlTableRowSpan([PSCustomObject[]] $Table, [String] $keyColumn) {
|
||||
$result = @(0) * $Table.Count
|
||||
|
||||
for ($rowIndex = $Table.Count - 1; $rowIndex -ge 0; $rowIndex--) {
|
||||
if (($rowIndex -lt ($Table.Count - 1)) -and ($Table[$rowIndex].$keyColumn -eq $Table[$rowIndex + 1].$keyColumn)) {
|
||||
# If the current row is the same as the next row
|
||||
# Then rowspan of current row should be equal to rowspan of the next row + 1
|
||||
# And rowspan of the next row should be 0 because it is already included in the rowspan of the current row
|
||||
$result[$rowIndex] = $result[$rowIndex + 1] + 1
|
||||
$result[$rowIndex + 1] = 0
|
||||
} else {
|
||||
$result[$rowIndex] = 1
|
||||
}
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
[String] RenderTableNodesDiff([ReportDifferenceItem] $DiffItem) {
|
||||
# Use the simplest approach for now: first, print all removed lines. Then print added lines
|
||||
# It will work well for most cases like changing existing rows, adding new rows and removing rows
|
||||
# But can produce not so pretty results for cases when some rows are changed and some rows are added at the same time
|
||||
# Let's see how it works in practice and improve it later if needed
|
||||
|
||||
[String] $tableHeaders = ($DiffItem.CurrentReportNode ?? $DiffItem.PreviousReportNode).Headers
|
||||
[Collections.Generic.List[String]] $tableRows = @()
|
||||
$DiffItem.PreviousReportNode.Rows ?? @() | Where-Object { $_ -notin $DiffItem.CurrentReportNode.Rows } | ForEach-Object {
|
||||
$tableRows.Add($this.StrikeTableRow($_))
|
||||
}
|
||||
$DiffItem.CurrentReportNode.Rows ?? @() | Where-Object { $_ -notin $DiffItem.PreviousReportNode.Rows } | ForEach-Object {
|
||||
$tableRows.Add($_)
|
||||
}
|
||||
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
$sb.AppendLine("#### $($this.RenderCategory($DiffItem.Headers, $false))")
|
||||
$sb.AppendLine([TableNode]::new($tableHeaders, $tableRows).ToMarkdown())
|
||||
return $sb.ToString()
|
||||
}
|
||||
|
||||
[String] RenderCategory([String[]] $Headers, [Boolean] $AddLineSeparator) {
|
||||
# Always skip the first header because it is "Installed Software"
|
||||
[String[]] $takeHeaders = $Headers | Select-Object -Skip 1
|
||||
if ($takeHeaders.Count -eq 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
$lineSeparator = $AddLineSeparator ? "<br>": ""
|
||||
return [String]::Join(" >$lineSeparator ", $takeHeaders)
|
||||
}
|
||||
|
||||
[String] RenderToolName([String] $ToolName) {
|
||||
return $ToolName.TrimEnd(":")
|
||||
}
|
||||
|
||||
[String] StrikeTableRow([String] $Row) {
|
||||
# Convert "a|b|c" to "~~a~~|~~b~~|~~c~~
|
||||
$cells = $Row.Split("|")
|
||||
$strikedCells = $cells | ForEach-Object { "~~$($_)~~"}
|
||||
return [String]::Join("|", $strikedCells)
|
||||
}
|
||||
}
|
||||
|
||||
# Temporary structure to store the single difference between two reports
|
||||
class ReportDifferenceItem {
|
||||
[BaseNode] $PreviousReportNode
|
||||
[BaseNode] $CurrentReportNode
|
||||
[String[]] $Headers
|
||||
|
||||
ReportDifferenceItem([BaseNode] $PreviousReportNode, [BaseNode] $CurrentReportNode, [String[]] $Headers) {
|
||||
$this.PreviousReportNode = $PreviousReportNode
|
||||
$this.CurrentReportNode = $CurrentReportNode
|
||||
$this.Headers = $Headers
|
||||
}
|
||||
|
||||
[Boolean] IsBaseToolNode() {
|
||||
$node = $this.CurrentReportNode ?? $this.PreviousReportNode
|
||||
return $node -is [BaseToolNode]
|
||||
}
|
||||
|
||||
[Boolean] IsTableNode() {
|
||||
$node = $this.CurrentReportNode ?? $this.PreviousReportNode
|
||||
return $node -is [TableNode]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
using module ./SoftwareReport.BaseNodes.psm1
|
||||
|
||||
#########################################
|
||||
### Nodes to describe image software ####
|
||||
#########################################
|
||||
|
||||
# NodesFactory is used to simplify parsing different types of notes
|
||||
# Every node has own logic of parsing and this method just invokes "FromJsonObject" of correct node type
|
||||
class NodesFactory {
|
||||
static [BaseNode] ParseNodeFromObject([object] $JsonObj) {
|
||||
if ($JsonObj.NodeType -eq [HeaderNode].Name) {
|
||||
return [HeaderNode]::FromJsonObject($JsonObj)
|
||||
} elseif ($JsonObj.NodeType -eq [ToolVersionNode].Name) {
|
||||
return [ToolVersionNode]::FromJsonObject($JsonObj)
|
||||
} elseif ($JsonObj.NodeType -eq [ToolVersionsListNode].Name) {
|
||||
return [ToolVersionsListNode]::FromJsonObject($JsonObj)
|
||||
} elseif ($JsonObj.NodeType -eq [TableNode].Name) {
|
||||
return [TableNode]::FromJsonObject($JsonObj)
|
||||
} elseif ($JsonObj.NodeType -eq [NoteNode].Name) {
|
||||
return [NoteNode]::FromJsonObject($JsonObj)
|
||||
}
|
||||
|
||||
throw "Unknown node type in ParseNodeFromObject '$($JsonObj.NodeType)'"
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderNode: BaseNode {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String] $Title
|
||||
[Collections.Generic.List[BaseNode]] $Children
|
||||
|
||||
HeaderNode([String] $Title) {
|
||||
$this.Title = $Title
|
||||
$this.Children = @()
|
||||
}
|
||||
|
||||
[Boolean] ShouldBeIncludedToDiff() {
|
||||
return $true
|
||||
}
|
||||
|
||||
[void] AddNode([BaseNode] $node) {
|
||||
$similarNode = $this.FindSimilarChildNode($node)
|
||||
if ($similarNode) {
|
||||
throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.`nFound node: $($similarNode.ToJsonObject() | ConvertTo-Json)`nNew node: $($node.ToJsonObject() | ConvertTo-Json)"
|
||||
}
|
||||
|
||||
if (-not $this.IsNodeHasMarkdownHeader($node)) {
|
||||
# If the node doesn't print own header to markdown, we should check that there is no other nodes that print header to markdown before it.
|
||||
# It is done to avoid unexpected situation like this:
|
||||
#
|
||||
# HeaderNode A -> # A
|
||||
# HeaderNode B -> ## B
|
||||
# ToolVersionNode C -> - C
|
||||
# ToolVersionNode D -> - D
|
||||
#
|
||||
# In this example, we add 'HeaderNode B" to 'HeaderNode A' and add 'ToolVersionNode C' to 'HeaderNode B'.
|
||||
# Then we add 'ToolVersionNode D' to 'HeaderNode A'.
|
||||
# But the result markdown will look like 'ToolVersionNode D' belongs to 'HeaderNode B' instead of 'HeaderNode A'.
|
||||
$this.Children | Where-Object { $this.IsNodeHasMarkdownHeader($_) } | ForEach-Object {
|
||||
throw "It is not allowed to add the non-header node after the header node. Consider adding the separate HeaderNode for this node"
|
||||
}
|
||||
}
|
||||
|
||||
$this.Children.Add($node)
|
||||
}
|
||||
|
||||
[void] AddNodes([BaseNode[]] $nodes) {
|
||||
$nodes | ForEach-Object {
|
||||
$this.AddNode($_)
|
||||
}
|
||||
}
|
||||
|
||||
[HeaderNode] AddHeader([String] $Title) {
|
||||
$node = [HeaderNode]::new($Title)
|
||||
$this.AddNode($node)
|
||||
return $node
|
||||
}
|
||||
|
||||
[void] AddToolVersion([String] $ToolName, [String] $Version) {
|
||||
$this.AddNode([ToolVersionNode]::new($ToolName, $Version))
|
||||
}
|
||||
|
||||
[void] AddToolVersionsList([String] $ToolName, [String[]] $Version, [String] $MajorVersionRegex) {
|
||||
$this.AddNode([ToolVersionsListNode]::new($ToolName, $Version, $MajorVersionRegex, "List"))
|
||||
}
|
||||
|
||||
[void] AddToolVersionsListInline([String] $ToolName, [String[]] $Version, [String] $MajorVersionRegex) {
|
||||
$this.AddNode([ToolVersionsListNode]::new($ToolName, $Version, $MajorVersionRegex, "Inline"))
|
||||
}
|
||||
|
||||
[void] AddTable([PSCustomObject[]] $Table) {
|
||||
$this.AddNode([TableNode]::FromObjectsArray($Table))
|
||||
}
|
||||
|
||||
[void] AddNote([String] $Content) {
|
||||
$this.AddNode([NoteNode]::new($Content))
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
$sb.AppendLine()
|
||||
$sb.AppendLine("$("#" * $Level) $($this.Title)")
|
||||
$this.Children | ForEach-Object {
|
||||
$sb.AppendLine($_.ToMarkdown($Level + 1))
|
||||
}
|
||||
|
||||
return $sb.ToString().TrimEnd()
|
||||
}
|
||||
|
||||
[PSCustomObject] ToJsonObject() {
|
||||
return [PSCustomObject]@{
|
||||
NodeType = $this.GetType().Name
|
||||
Title = $this.Title
|
||||
Children = $this.Children | ForEach-Object { $_.ToJsonObject() }
|
||||
}
|
||||
}
|
||||
|
||||
static [HeaderNode] FromJsonObject([Object] $JsonObj) {
|
||||
$node = [HeaderNode]::new($JsonObj.Title)
|
||||
$JsonObj.Children | Where-Object { $_ } | ForEach-Object { $node.AddNode([NodesFactory]::ParseNodeFromObject($_)) }
|
||||
return $node
|
||||
}
|
||||
|
||||
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
|
||||
if ($OtherNode.GetType() -ne [HeaderNode]) {
|
||||
return $false
|
||||
}
|
||||
|
||||
return $this.Title -eq $OtherNode.Title
|
||||
}
|
||||
|
||||
[Boolean] IsIdenticalTo([BaseNode] $OtherNode) {
|
||||
return $this.IsSimilarTo($OtherNode)
|
||||
}
|
||||
|
||||
[BaseNode] FindSimilarChildNode([BaseNode] $Find) {
|
||||
foreach ($childNode in $this.Children) {
|
||||
if ($childNode.IsSimilarTo($Find)) {
|
||||
return $childNode
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
hidden [Boolean] IsNodeHasMarkdownHeader([BaseNode] $node) {
|
||||
if ($node -is [HeaderNode]) {
|
||||
return $true
|
||||
}
|
||||
|
||||
if (($node -is [ToolVersionsListNode]) -and ($node.ListType -eq "List")) {
|
||||
return $true
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
class ToolVersionNode: BaseToolNode {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String] $Version
|
||||
|
||||
ToolVersionNode([String] $ToolName, [String] $Version): base($ToolName) {
|
||||
$this.Version = $Version
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
return "- $($this.ToolName) $($this.Version)"
|
||||
}
|
||||
|
||||
[String] GetValue() {
|
||||
return $this.Version
|
||||
}
|
||||
|
||||
[PSCustomObject] ToJsonObject() {
|
||||
return [PSCustomObject]@{
|
||||
NodeType = $this.GetType().Name
|
||||
ToolName = $this.ToolName
|
||||
Version = $this.Version
|
||||
}
|
||||
}
|
||||
|
||||
static [BaseNode] FromJsonObject([Object] $JsonObj) {
|
||||
return [ToolVersionNode]::new($JsonObj.ToolName, $JsonObj.Version)
|
||||
}
|
||||
}
|
||||
|
||||
class ToolVersionsListNode: BaseToolNode {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String[]] $Versions
|
||||
|
||||
[Regex] $MajorVersionRegex
|
||||
|
||||
[ValidateSet("List", "Inline")]
|
||||
[String] $ListType
|
||||
|
||||
ToolVersionsListNode([String] $ToolName, [String[]] $Versions, [String] $MajorVersionRegex, [String] $ListType): base($ToolName) {
|
||||
$this.Versions = $Versions
|
||||
$this.MajorVersionRegex = [Regex]::new($MajorVersionRegex)
|
||||
$this.ListType = $ListType
|
||||
$this.ValidateMajorVersionRegex()
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
if ($this.ListType -eq "Inline") {
|
||||
return "- $($this.ToolName): $($this.Versions -join ', ')"
|
||||
}
|
||||
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
$sb.AppendLine()
|
||||
$sb.AppendLine("$("#" * $Level) $($this.ToolName)")
|
||||
$this.Versions | ForEach-Object {
|
||||
$sb.AppendLine("- $_")
|
||||
}
|
||||
|
||||
return $sb.ToString().TrimEnd()
|
||||
}
|
||||
|
||||
[String] GetValue() {
|
||||
return $this.Versions -join ', '
|
||||
}
|
||||
|
||||
[String] ExtractMajorVersion([String] $Version) {
|
||||
$match = $this.MajorVersionRegex.Match($Version)
|
||||
if (($match.Success -ne $true) -or [String]::IsNullOrEmpty($match.Groups[0].Value)) {
|
||||
throw "Version '$Version' doesn't match regex '$($this.PrimaryVersionRegex)'"
|
||||
}
|
||||
|
||||
return $match.Groups[0].Value
|
||||
}
|
||||
|
||||
[PSCustomObject] ToJsonObject() {
|
||||
return [PSCustomObject]@{
|
||||
NodeType = $this.GetType().Name
|
||||
ToolName = $this.ToolName
|
||||
Versions = $this.Versions
|
||||
MajorVersionRegex = $this.MajorVersionRegex.ToString()
|
||||
ListType = $this.ListType
|
||||
}
|
||||
}
|
||||
|
||||
static [ToolVersionsListNode] FromJsonObject([Object] $JsonObj) {
|
||||
return [ToolVersionsListNode]::new($JsonObj.ToolName, $JsonObj.Versions, $JsonObj.MajorVersionRegex, $JsonObj.ListType)
|
||||
}
|
||||
|
||||
hidden [void] ValidateMajorVersionRegex() {
|
||||
$this.Versions | Group-Object { $this.ExtractMajorVersion($_) } | ForEach-Object {
|
||||
if ($_.Count -gt 1) {
|
||||
throw "Multiple versions from list '$($this.GetValue())' return the same result from regex '$($this.MajorVersionRegex)': $($_.Name)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TableNode: BaseNode {
|
||||
# It is easier to store the table as rendered lines because it will simplify finding differences in rows later
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String] $Headers
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String[]] $Rows
|
||||
|
||||
TableNode([String] $Headers, [String[]] $Rows) {
|
||||
$this.Headers = $Headers
|
||||
$this.Rows = $Rows
|
||||
|
||||
$columnsCount = $this.Headers.Split("|").Count
|
||||
$this.Rows | ForEach-Object {
|
||||
if ($_.Split("|").Count -ne $columnsCount) {
|
||||
throw "Table has different number of columns in different rows"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Boolean] ShouldBeIncludedToDiff() {
|
||||
return $true
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
$maxColumnWidths = $this.CalculateColumnsWidth()
|
||||
$columnsCount = $maxColumnWidths.Count
|
||||
|
||||
$delimiterLine = [String]::Join("|", @("-") * $columnsCount)
|
||||
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
@($this.Headers) + @($delimiterLine) + $this.Rows | ForEach-Object {
|
||||
$sb.Append("|")
|
||||
$row = $_.Split("|")
|
||||
|
||||
for ($colIndex = 0; $colIndex -lt $columnsCount; $colIndex++) {
|
||||
$padSymbol = $row[$colIndex] -eq "-" ? "-" : " "
|
||||
$cellContent = $row[$colIndex].PadRight($maxColumnWidths[$colIndex], $padSymbol)
|
||||
$sb.Append(" $($cellContent) |")
|
||||
}
|
||||
|
||||
$sb.AppendLine()
|
||||
}
|
||||
|
||||
return $sb.ToString().TrimEnd()
|
||||
}
|
||||
|
||||
hidden [Int32[]] CalculateColumnsWidth() {
|
||||
$maxColumnWidths = $this.Headers.Split("|") | ForEach-Object { $_.Length }
|
||||
$columnsCount = $maxColumnWidths.Count
|
||||
|
||||
$this.Rows | ForEach-Object {
|
||||
$columnWidths = $_.Split("|") | ForEach-Object { $_.Length }
|
||||
for ($colIndex = 0; $colIndex -lt $columnsCount; $colIndex++) {
|
||||
$maxColumnWidths[$colIndex] = [Math]::Max($maxColumnWidths[$colIndex], $columnWidths[$colIndex])
|
||||
}
|
||||
}
|
||||
|
||||
return $maxColumnWidths
|
||||
}
|
||||
|
||||
[PSCustomObject] ToJsonObject() {
|
||||
return [PSCustomObject]@{
|
||||
NodeType = $this.GetType().Name
|
||||
Headers = $this.Headers
|
||||
Rows = $this.Rows
|
||||
}
|
||||
}
|
||||
|
||||
static [TableNode] FromJsonObject([Object] $JsonObj) {
|
||||
return [TableNode]::new($JsonObj.Headers, $JsonObj.Rows)
|
||||
}
|
||||
|
||||
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
|
||||
if ($OtherNode.GetType() -ne [TableNode]) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# We don't support having multiple TableNode instances on the same header level so such check is fine
|
||||
return $true
|
||||
}
|
||||
|
||||
[Boolean] IsIdenticalTo([BaseNode] $OtherNode) {
|
||||
if (-not $this.IsSimilarTo($OtherNode)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# We don't compare $this.Headers intentionally
|
||||
# It is fine to ignore the tables where headers are changed but rows are not changed
|
||||
|
||||
if ($this.Rows.Count -ne $OtherNode.Rows.Count) {
|
||||
return $false
|
||||
}
|
||||
|
||||
for ($rowIndex = 0; $rowIndex -lt $this.Rows.Count; $rowIndex++) {
|
||||
if ($this.Rows[$rowIndex] -ne $OtherNode.Rows[$rowIndex]) {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
static [TableNode] FromObjectsArray([PSCustomObject[]] $Table) {
|
||||
if ($Table.Count -eq 0) {
|
||||
throw "Failed to create TableNode from empty objects array"
|
||||
}
|
||||
|
||||
[String] $tableHeaders = [TableNode]::ArrayToTableRow($Table[0].PSObject.Properties.Name)
|
||||
[Collections.Generic.List[String]] $tableRows = @()
|
||||
|
||||
$Table | ForEach-Object {
|
||||
$rowHeaders = [TableNode]::ArrayToTableRow($_.PSObject.Properties.Name)
|
||||
if (($rowHeaders -ne $tableHeaders)) {
|
||||
throw "Failed to create TableNode from objects array because objects have different properties"
|
||||
}
|
||||
|
||||
$tableRows.Add([TableNode]::ArrayToTableRow($_.PSObject.Properties.Value))
|
||||
}
|
||||
|
||||
return [TableNode]::new($tableHeaders, $tableRows)
|
||||
}
|
||||
|
||||
hidden static [String] ArrayToTableRow([String[]] $Values) {
|
||||
if ($Values.Count -eq 0) {
|
||||
throw "Failed to create TableNode because some objects are empty"
|
||||
}
|
||||
$Values | ForEach-Object {
|
||||
if ($_.Contains("|")) {
|
||||
throw "Failed to create TableNode because some cells '$_' contains forbidden symbol '|'"
|
||||
}
|
||||
}
|
||||
|
||||
return [String]::Join("|", $Values)
|
||||
}
|
||||
}
|
||||
|
||||
class NoteNode: BaseNode {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String] $Content
|
||||
|
||||
NoteNode([String] $Content) {
|
||||
$this.Content = $Content
|
||||
}
|
||||
|
||||
[String] ToMarkdown([Int32] $Level) {
|
||||
return @(
|
||||
'```',
|
||||
$this.Content,
|
||||
'```'
|
||||
) -join "`n"
|
||||
}
|
||||
|
||||
[PSCustomObject] ToJsonObject() {
|
||||
return [PSCustomObject]@{
|
||||
NodeType = $this.GetType().Name
|
||||
Content = $this.Content
|
||||
}
|
||||
}
|
||||
|
||||
static [NoteNode] FromJsonObject([Object] $JsonObj) {
|
||||
return [NoteNode]::new($JsonObj.Content)
|
||||
}
|
||||
|
||||
[Boolean] IsSimilarTo([BaseNode] $OtherNode) {
|
||||
if ($OtherNode.GetType() -ne [NoteNode]) {
|
||||
return $false
|
||||
}
|
||||
|
||||
return $this.Content -eq $OtherNode.Content
|
||||
}
|
||||
|
||||
[Boolean] IsIdenticalTo([BaseNode] $OtherNode) {
|
||||
return $this.IsSimilarTo($OtherNode)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using module ./SoftwareReport.BaseNodes.psm1
|
||||
using module ./SoftwareReport.Nodes.psm1
|
||||
|
||||
class SoftwareReport {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[HeaderNode] $Root
|
||||
|
||||
SoftwareReport([String] $Title) {
|
||||
$this.Root = [HeaderNode]::new($Title)
|
||||
}
|
||||
|
||||
SoftwareReport([HeaderNode] $Root) {
|
||||
$this.Root = $Root
|
||||
}
|
||||
|
||||
[String] ToJson() {
|
||||
return $this.Root.ToJsonObject() | ConvertTo-Json -Depth 10
|
||||
}
|
||||
|
||||
static [SoftwareReport] FromJson([String] $JsonString) {
|
||||
$jsonObj = $JsonString | ConvertFrom-Json
|
||||
$rootNode = [NodesFactory]::ParseNodeFromObject($jsonObj)
|
||||
return [SoftwareReport]::new($rootNode)
|
||||
}
|
||||
|
||||
[String] ToMarkdown() {
|
||||
return $this.Root.ToMarkdown().Trim()
|
||||
}
|
||||
|
||||
[String] GetImageVersion() {
|
||||
$imageVersionNode = $this.Root.Children ?? @() | Where-Object { ($_ -is [ToolVersionNode]) -and ($_.ToolName -eq "Image Version:") } | Select-Object -First 1
|
||||
return $imageVersionNode.Version ?? "Unknown version"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
using module ../SoftwareReport.psm1
|
||||
using module ../SoftwareReport.DifferenceCalculator.psm1
|
||||
|
||||
Describe "Comparer.E2E" {
|
||||
It "Some tools are updated" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.1 (20G817)")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$prevTools = $prevInstalledSoftware.AddHeader("Tools")
|
||||
$prevTools.AddToolVersion("ToolWillBeUpdated1", "1.0.0")
|
||||
$prevTools.AddToolVersion("ToolWillBeUpdated2", "3.0.1")
|
||||
$prevTools.AddToolVersionsList("ToolWillBeUpdated3", @("14.0.0", "15.5.1"), "^\d+")
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.1 (20G817)")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.1")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$nextTools = $nextInstalledSoftware.AddHeader("Tools")
|
||||
$nextTools.AddToolVersion("ToolWillBeUpdated1", "2.5.0")
|
||||
$nextTools.AddToolVersion("ToolWillBeUpdated2", "3.0.2")
|
||||
$nextTools.AddToolVersionsList("ToolWillBeUpdated3", @("14.2.0", "15.5.1"), "^\d+")
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- OS Version: macOS 11.7.1 (20G817)
|
||||
- Image Version: 20220922.1
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
### Updated
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Previous (20220918.1)</th>
|
||||
<th>Current (20220922.1)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">Tools</td>
|
||||
<td>ToolWillBeUpdated1</td>
|
||||
<td>1.0.0</td>
|
||||
<td>2.5.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ToolWillBeUpdated2</td>
|
||||
<td>3.0.1</td>
|
||||
<td>3.0.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ToolWillBeUpdated3</td>
|
||||
<td>14.0.0</td>
|
||||
<td>14.2.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Some tools are updated, added and removed" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.1 (20G817)")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
|
||||
$prevLanguagesAndRuntimes = $prevInstalledSoftware.AddHeader("Language and Runtime")
|
||||
$prevLanguagesAndRuntimes.AddToolVersion("ToolWillBeRemoved", "5.1.16(1)-release")
|
||||
$prevLanguagesAndRuntimes.AddToolVersionsListInline("ToolWithMultipleVersions3", @("1.2.100", "1.2.200", "1.3.500", "1.4.100", "1.4.200"), "^\d+\.\d+\.\d")
|
||||
$prevLanguagesAndRuntimes.AddToolVersion("ToolWithoutChanges", "5.34.0")
|
||||
$prevLanguagesAndRuntimes.AddToolVersion("ToolWillBeUpdated", "8.1.0")
|
||||
|
||||
$prevCachedTools = $prevInstalledSoftware.AddHeader("Cached Tools")
|
||||
$prevCachedTools.AddToolVersionsList("ToolWithMultipleVersions1", @("2.7.3", "2.8.1", "3.1.2"), "^\d+\.\d+")
|
||||
$prevCachedTools.AddToolVersionsList("ToolWithMultipleVersions2", @("14.8.0", "15.1.0", "16.4.2"), "^\d+")
|
||||
|
||||
$prevSQLSection = $prevInstalledSoftware.AddHeader("Databases")
|
||||
$prevSQLSection.AddToolVersion("MineSQL", "6.1.0")
|
||||
$prevSQLSection.AddNote("First Note")
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.2 (20G922)")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.0")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
|
||||
$nextLanguagesAndRuntimes = $nextInstalledSoftware.AddHeader("Language and Runtime")
|
||||
$nextLanguagesAndRuntimes.AddToolVersion("ToolWillBeAdded", "16.18.0")
|
||||
$nextLanguagesAndRuntimes.AddToolVersionsListInline("ToolWithMultipleVersions3", @("1.2.200", "1.3.515", "1.4.100", "1.4.200", "1.5.800"), "^\d+\.\d+\.\d")
|
||||
$nextLanguagesAndRuntimes.AddToolVersion("ToolWithoutChanges", "5.34.0")
|
||||
$nextLanguagesAndRuntimes.AddToolVersion("ToolWillBeUpdated", "8.3.0")
|
||||
|
||||
$nextCachedTools = $nextInstalledSoftware.AddHeader("Cached Tools")
|
||||
$nextCachedTools.AddToolVersionsList("ToolWithMultipleVersions1", @("2.7.3", "2.8.1", "3.1.2"), "^\d+\.\d+")
|
||||
$nextCachedTools.AddToolVersionsList("ToolWithMultipleVersions2", @("15.1.0", "16.4.2", "17.0.1"), "^\d+")
|
||||
|
||||
$nextSQLSection = $nextInstalledSoftware.AddHeader("Databases")
|
||||
$nextSQLSection.AddToolVersion("MineSQL", "6.1.1")
|
||||
$nextSQLSection.AddNote("Second Note")
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- OS Version: macOS 11.7.2 (20G922)
|
||||
- Image Version: 20220922.0
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
### Added :heavy_plus_sign:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Current (20220922.0)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="2">Language and Runtime</td>
|
||||
<td>ToolWillBeAdded</td>
|
||||
<td>16.18.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ToolWithMultipleVersions3</td>
|
||||
<td>1.5.800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">Cached Tools</td>
|
||||
<td>ToolWithMultipleVersions2</td>
|
||||
<td>17.0.1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Deleted :heavy_minus_sign:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Previous (20220918.1)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="2">Language and Runtime</td>
|
||||
<td>ToolWithMultipleVersions3</td>
|
||||
<td>1.2.100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ToolWillBeRemoved</td>
|
||||
<td>5.1.16(1)-release</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">Cached Tools</td>
|
||||
<td>ToolWithMultipleVersions2</td>
|
||||
<td>14.8.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Updated
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Previous (20220918.1)</th>
|
||||
<th>Current (20220922.0)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1"></td>
|
||||
<td>OS Version</td>
|
||||
<td>macOS 11.7.1 (20G817)</td>
|
||||
<td>macOS 11.7.2 (20G922)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">Language and Runtime</td>
|
||||
<td>ToolWithMultipleVersions3</td>
|
||||
<td>1.3.500</td>
|
||||
<td>1.3.515</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ToolWillBeUpdated</td>
|
||||
<td>8.1.0</td>
|
||||
<td>8.3.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">Databases</td>
|
||||
<td>MineSQL</td>
|
||||
<td>6.1.0</td>
|
||||
<td>6.1.1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Header tree changes" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$prevInstalledSoftware.AddToolVersion("ToolWithoutChanges", "5.34.0")
|
||||
$prevInstalledSoftware.AddHeader("HeaderWillBeRemoved").AddHeader("SubheaderWillBeRemoved").AddToolVersion("ToolWillBeRemoved", "1.0.0")
|
||||
$prevInstalledSoftware.AddHeader("Header1").AddToolVersion("ToolWillBeMovedToAnotherHeader", "3.0.0")
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.0")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$nextInstalledSoftware.AddToolVersion("ToolWithoutChanges", "5.34.0")
|
||||
$nextInstalledSoftware.AddHeader("HeaderWillBeAdded").AddHeader("SubheaderWillBeAdded").AddToolVersion("ToolWillBeAdded", "5.0.0")
|
||||
$nextInstalledSoftware.AddHeader("Header2").AddToolVersion("ToolWillBeMovedToAnotherHeader", "3.0.0")
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- Image Version: 20220922.0
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
### Added :heavy_plus_sign:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Current (20220922.0)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1">HeaderWillBeAdded ><br> SubheaderWillBeAdded</td>
|
||||
<td>ToolWillBeAdded</td>
|
||||
<td>5.0.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">Header2</td>
|
||||
<td>ToolWillBeMovedToAnotherHeader</td>
|
||||
<td>3.0.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Deleted :heavy_minus_sign:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Previous (20220918.1)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1">HeaderWillBeRemoved ><br> SubheaderWillBeRemoved</td>
|
||||
<td>ToolWillBeRemoved</td>
|
||||
<td>1.0.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">Header1</td>
|
||||
<td>ToolWillBeMovedToAnotherHeader</td>
|
||||
<td>3.0.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Tables are added and removed" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$prevInstalledSoftware.AddHeader("HeaderWillExist").AddTable(@(
|
||||
[PSCustomObject]@{TableInExistingHeaderWillBeRemoved = "Q"; Value = "25"},
|
||||
[PSCustomObject]@{TableInExistingHeaderWillBeRemoved = "O"; Value = "24"}
|
||||
))
|
||||
|
||||
$prevTools = $prevInstalledSoftware.AddHeader("Tools")
|
||||
$prevTools.AddHeader("HeaderWillBeRemoved").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "Z"; Value = "30"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "W"; Value = "29"}
|
||||
))
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.1")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$nextInstalledSoftware.AddHeader("HeaderWillExist")
|
||||
$nextTools = $nextInstalledSoftware.AddHeader("Tools")
|
||||
$nextTools.AddToolVersion("ToolWillBeAdded", "3.0.1")
|
||||
$nextTools.AddTable(@(
|
||||
[PSCustomObject]@{NewTableInExistingHeader = "A"; Value = "1"},
|
||||
[PSCustomObject]@{NewTableInExistingHeader = "B"; Value = "2"}
|
||||
))
|
||||
$nextTools.AddHeader("NewHeaderWithTable").AddTable(@(
|
||||
[PSCustomObject]@{NewTableInNewHeader = "C"; Value = "3"},
|
||||
[PSCustomObject]@{NewTableInNewHeader = "D"; Value = "4"}
|
||||
))
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- Image Version: 20220922.1
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
### Added :heavy_plus_sign:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Current (20220922.1)</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1">Tools</td>
|
||||
<td>ToolWillBeAdded</td>
|
||||
<td>3.0.1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
#### Tools
|
||||
| NewTableInExistingHeader | Value |
|
||||
| ------------------------ | ----- |
|
||||
| A | 1 |
|
||||
| B | 2 |
|
||||
|
||||
#### Tools > NewHeaderWithTable
|
||||
| NewTableInNewHeader | Value |
|
||||
| ------------------- | ----- |
|
||||
| C | 3 |
|
||||
| D | 4 |
|
||||
|
||||
### Deleted :heavy_minus_sign:
|
||||
|
||||
#### HeaderWillExist
|
||||
| TableInExistingHeaderWillBeRemoved | Value |
|
||||
| ---------------------------------- | ------ |
|
||||
| ~~Q~~ | ~~25~~ |
|
||||
| ~~O~~ | ~~24~~ |
|
||||
|
||||
#### Tools > HeaderWillBeRemoved
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ------ |
|
||||
| ~~Z~~ | ~~30~~ |
|
||||
| ~~W~~ | ~~29~~ |
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Tables are changed" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$prevTools = $prevInstalledSoftware.AddHeader("Tools")
|
||||
$prevTools.AddHeader("TableWithAddedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "AA"; Value = "10"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "AB"; Value = "11"}
|
||||
))
|
||||
$prevTools.AddHeader("TableWithRemovedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "BA"; Value = "32"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "BB"; Value = "33"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "BC"; Value = "34"}
|
||||
))
|
||||
$prevTools.AddHeader("TableWithUpdatedRow").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CA"; Value = "42"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CB"; Value = "43"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CC"; Value = "44"}
|
||||
))
|
||||
$prevTools.AddHeader("TableWithUpdatedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DA"; Value = "50"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DB"; Value = "51"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DC"; Value = "52"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DD"; Value = "53"}
|
||||
))
|
||||
$prevTools.AddHeader("TableWithComplexChanges").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EA"; Value = "62"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EB"; Value = "63"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EC"; Value = "64"}
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "ED"; Value = "65"}
|
||||
))
|
||||
|
||||
$prevTools.AddHeader("TableWithOnlyHeaderChanged").AddTable(@(
|
||||
[PSCustomObject]@{TableWithOnlyHeaderChanged = "FA"; Value = "72"},
|
||||
[PSCustomObject]@{TableWithOnlyHeaderChanged = "FB"; Value = "73"}
|
||||
))
|
||||
|
||||
$prevTools.AddHeader("TableWithHeaderAndRowsChanges").AddTable(@(
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges = "GA"; Value = "82"},
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges = "GB"; Value = "83"},
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges = "GC"; Value = "84"}
|
||||
))
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.1")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$nextTools = $nextInstalledSoftware.AddHeader("Tools")
|
||||
$nextTools.AddHeader("TableWithAddedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "AA"; Value = "10"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "AB"; Value = "11"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "AC"; Value = "12"}
|
||||
))
|
||||
$nextTools.AddHeader("TableWithRemovedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "BB"; Value = "33"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "BC"; Value = "34"}
|
||||
))
|
||||
$nextTools.AddHeader("TableWithUpdatedRow").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CA"; Value = "42"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CB"; Value = "500"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "CC"; Value = "44"}
|
||||
))
|
||||
$nextTools.AddHeader("TableWithUpdatedRows").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DA"; Value = "50"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DB"; Value = "5100"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DC"; Value = "5200"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "DD"; Value = "53"}
|
||||
))
|
||||
$nextTools.AddHeader("TableWithComplexChanges").AddTable(@(
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EB"; Value = "63"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EC"; Value = "640"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "ED"; Value = "65"},
|
||||
[PSCustomObject]@{TableWillBeRemovedWithHeader = "EE"; Value = "66"}
|
||||
))
|
||||
|
||||
$nextTools.AddHeader("TableWithOnlyHeaderChanged").AddTable(@(
|
||||
[PSCustomObject]@{TableWithOnlyHeaderChanged2 = "FA"; Value = "72"},
|
||||
[PSCustomObject]@{TableWithOnlyHeaderChanged2 = "FB"; Value = "73"}
|
||||
))
|
||||
|
||||
$nextTools.AddHeader("TableWithHeaderAndRowsChanges").AddTable(@(
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges2 = "GA"; Value = "82"},
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges2 = "GE"; Value = "850"},
|
||||
[PSCustomObject]@{TableWithHeaderAndRowsChanges2 = "GC"; Value = "840"}
|
||||
))
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- Image Version: 20220922.1
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
### Added :heavy_plus_sign:
|
||||
|
||||
#### Tools > TableWithAddedRows
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ----- |
|
||||
| AC | 12 |
|
||||
|
||||
#### Tools > TableWithHeaderAndRowsChanges
|
||||
| TableWithHeaderAndRowsChanges2 | Value |
|
||||
| ------------------------------ | ----- |
|
||||
| GA | 82 |
|
||||
| GE | 850 |
|
||||
| GC | 840 |
|
||||
|
||||
### Deleted :heavy_minus_sign:
|
||||
|
||||
#### Tools > TableWithRemovedRows
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ------ |
|
||||
| ~~BA~~ | ~~32~~ |
|
||||
|
||||
#### Tools > TableWithHeaderAndRowsChanges
|
||||
| TableWithHeaderAndRowsChanges | Value |
|
||||
| ----------------------------- | ------ |
|
||||
| ~~GA~~ | ~~82~~ |
|
||||
| ~~GB~~ | ~~83~~ |
|
||||
| ~~GC~~ | ~~84~~ |
|
||||
|
||||
### Updated
|
||||
|
||||
#### Tools > TableWithUpdatedRow
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ------ |
|
||||
| ~~CB~~ | ~~43~~ |
|
||||
| CB | 500 |
|
||||
|
||||
#### Tools > TableWithUpdatedRows
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ------ |
|
||||
| ~~DB~~ | ~~51~~ |
|
||||
| ~~DC~~ | ~~52~~ |
|
||||
| DB | 5100 |
|
||||
| DC | 5200 |
|
||||
|
||||
#### Tools > TableWithComplexChanges
|
||||
| TableWillBeRemovedWithHeader | Value |
|
||||
| ---------------------------- | ------ |
|
||||
| ~~EA~~ | ~~62~~ |
|
||||
| ~~EC~~ | ~~64~~ |
|
||||
| EC | 640 |
|
||||
| EE | 66 |
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Reports are identical" {
|
||||
# Previous report
|
||||
$prevSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$prevSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.1 (20G817)")
|
||||
$prevSoftwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$prevInstalledSoftware = $prevSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$prevTools = $prevInstalledSoftware.AddHeader("Tools")
|
||||
$prevTools.AddToolVersion("ToolA", "1.0.0")
|
||||
$prevTools.AddToolVersion("ToolB", "3.0.1")
|
||||
|
||||
# Next report
|
||||
$nextSoftwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$nextSoftwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7.1 (20G817)")
|
||||
$nextSoftwareReport.Root.AddToolVersion("Image Version:", "20220922.1")
|
||||
$nextInstalledSoftware = $nextSoftwareReport.Root.AddHeader("Installed Software")
|
||||
$nextTools = $nextInstalledSoftware.AddHeader("Tools")
|
||||
$nextTools.AddToolVersion("ToolA", "1.0.0")
|
||||
$nextTools.AddToolVersion("ToolB", "3.0.1")
|
||||
|
||||
# Compare reports
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevSoftwareReport, $nextSoftwareReport)
|
||||
$comparer.CompareReports()
|
||||
$comparer.GetMarkdownReport() | Should -BeExactly @'
|
||||
# :desktop_computer: Actions Runner Image: macOS 11
|
||||
- OS Version: macOS 11.7.1 (20G817)
|
||||
- Image Version: 20220922.1
|
||||
|
||||
## :mega: What's changed?
|
||||
|
||||
|
||||
'@
|
||||
}
|
||||
}
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
using module ../SoftwareReport.Nodes.psm1
|
||||
using module ../SoftwareReport.DifferenceCalculator.psm1
|
||||
|
||||
BeforeDiscovery {
|
||||
Import-Module $(Join-Path $PSScriptRoot "TestHelpers.psm1") -DisableNameChecking
|
||||
}
|
||||
|
||||
Describe "Comparer.UnitTests" {
|
||||
Describe "Headers Tree" {
|
||||
It "Add Node to existing header" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.AddedItems[0].Headers | Should -BeArray @("MyHeader")
|
||||
}
|
||||
|
||||
It "Add new header with Node" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddHeader("MySubHeader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.AddedItems[0].Headers | Should -BeArray @("MyHeader", "MySubHeader")
|
||||
}
|
||||
|
||||
It "Remove Node from existing header" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
$comparer.DeletedItems[0].Headers | Should -BeArray @("MyHeader")
|
||||
}
|
||||
|
||||
It "Remove header with Node" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
$comparer.DeletedItems[0].Headers | Should -BeArray @("MyHeader", "MySubheader")
|
||||
}
|
||||
|
||||
It "Node with minor changes" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.4")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Version | Should -Be "2.1.4"
|
||||
$comparer.ChangedItems[0].Headers | Should -BeArray @("MyHeader", "MySubHeader")
|
||||
}
|
||||
|
||||
It "Node without changes" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
}
|
||||
|
||||
It "Node is moved to different header" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddHeader("MySubheader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddHeader("MySubheader2").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.AddedItems[0].Headers | Should -BeArray @("MyHeader", "MySubheader2")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
$comparer.DeletedItems[0].Headers | Should -BeArray @("MyHeader", "MySubheader")
|
||||
}
|
||||
|
||||
It "Complex structure" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevSubHeader = $prevReport.AddHeader("MyHeader").AddHeader("MySubheader")
|
||||
$prevSubHeader.AddToolVersion("MyTool1", "2.1.3")
|
||||
$prevSubHeader.AddHeader("MySubSubheader").AddToolVersion("MyTool2", "2.9.1")
|
||||
$prevReport.AddHeader("MyHeader2")
|
||||
$prevReport.AddHeader("MyHeader3").AddHeader("MySubheader3").AddToolVersion("MyTool3", "14.2.1")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextSubHeader = $nextReport.AddHeader("MyHeader").AddHeader("MySubheader")
|
||||
$nextSubHeader.AddToolVersion("MyTool1", "2.1.4")
|
||||
$nextSubSubHeader = $nextSubHeader.AddHeader("MySubSubheader")
|
||||
$nextSubSubHeader.AddToolVersion("MyTool2", "2.9.1")
|
||||
$nextSubSubHeader.AddToolVersion("MyTool4", "2.7.6")
|
||||
$nextReport.AddHeader("MyHeader2")
|
||||
$nextReport.AddHeader("MyHeader3")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool4"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Version | Should -Be "2.7.6"
|
||||
$comparer.AddedItems[0].Headers | Should -BeArray @("MyHeader", "MySubheader", "MySubSubheader")
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Version | Should -Be "2.1.4"
|
||||
$comparer.ChangedItems[0].Headers | Should -BeArray @("MyHeader", "MySubheader")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool3"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Version | Should -Be "14.2.1"
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
$comparer.DeletedItems[0].Headers | Should -BeArray @("MyHeader3", "MySubheader3")
|
||||
}
|
||||
}
|
||||
|
||||
Describe "ToolVersionNode" {
|
||||
It "ToolVersionNode is updated" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersion("MyTool1", "2.1.3")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersion("MyTool1", "2.1.4")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Version | Should -Be "2.1.3"
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Version | Should -Be "2.1.4"
|
||||
$comparer.ChangedItems[0].Headers | Should -BeArray @("MyHeader")
|
||||
}
|
||||
}
|
||||
|
||||
Describe "ToolVersionsListNode" {
|
||||
It "Single version is not changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3"), "^.+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3"), "^.+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
}
|
||||
|
||||
It "Single version is changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3"), "^\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.4"), "^\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Versions | Should -BeArray @("2.1.3")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Versions | Should -BeArray @("2.1.4")
|
||||
}
|
||||
|
||||
It "Major version is added" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3"), "^\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3", "3.1.4"), "^\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Versions | Should -BeArray @("3.1.4")
|
||||
}
|
||||
|
||||
It "Major version is removed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3", "3.1.4"), "^\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("3.1.4"), "^\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Versions | Should -BeArray @("2.1.3")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Major version is changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("3.1.4"), "^\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("3.2.0"), "^\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Versions | Should -BeArray @("3.1.4")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Versions | Should -BeArray @("3.2.0")
|
||||
}
|
||||
|
||||
It "Major version is added, removed and updated at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("1.0.0", "2.1.3", "3.1.4", "4.0.2"), "^\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.1.3", "3.2.0", "4.0.2", "5.1.0"), "^\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Versions | Should -BeArray @("5.1.0")
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Versions | Should -BeArray @("3.1.4")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Versions | Should -BeArray @("3.2.0")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Versions | Should -BeArray @("1.0.0")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Minor version is added, removed and updated at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.3.8", "2.4.9", "2.5.3", "2.6.0", "2.7.4", "2.8.0"), "^\d+\.\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.5.3", "2.6.2", "2.7.5", "2.8.0", "2.9.2", "2.10.3"), "^\d+\.\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Versions | Should -BeArray @("2.9.2", "2.10.3")
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Versions | Should -BeArray @("2.6.0", "2.7.4")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Versions | Should -BeArray @("2.6.2", "2.7.5")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Versions | Should -BeArray @("2.3.8", "2.4.9")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Patch version is added, removed and updated at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.3.8", "2.4.9", "2.5.3", "2.6.0", "2.7.4"), "^\d+\.\d+\.\d+")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddToolVersionsList("MyTool1", @("2.4.9", "2.5.4", "2.6.0", "2.7.5", "2.8.2"), "^\d+\.\d+\.\d+")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Versions | Should -BeArray @("2.5.4", "2.7.5", "2.8.2")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([ToolVersionsListNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.ToolName | Should -Be "MyTool1"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Versions | Should -BeArray @("2.3.8", "2.5.3", "2.7.4")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
Describe "TableNode" {
|
||||
It "Rows are added" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2", "C1|C2", "D1|D2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.AddedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.AddedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2")
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2", "C1|C2", "D1|D2")
|
||||
}
|
||||
|
||||
It "Rows are deleted" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2", "C1|C2", "D1|D2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("C1|C2", "D1|D2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2", "C1|C2", "D1|D2")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.DeletedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.DeletedItems[0].CurrentReportNode.Rows | Should -BeArray @("C1|C2", "D1|D2")
|
||||
}
|
||||
|
||||
It "Rows are changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B3|B4")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Rows | Should -BeArray @("A1|A2", "B3|B4")
|
||||
}
|
||||
|
||||
It "Rows are changed and updated at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B3|B4", "C1|C2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Rows | Should -BeArray @("A1|A2", "B3|B4", "C1|C2")
|
||||
}
|
||||
|
||||
It "Rows are changed and removed at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2", "C1|C2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B3|B4")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 1
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
|
||||
$comparer.ChangedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2", "C1|C2")
|
||||
$comparer.ChangedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.ChangedItems[0].CurrentReportNode.Rows | Should -BeArray @("A1|A2", "B3|B4")
|
||||
}
|
||||
|
||||
It "Rows are not changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
}
|
||||
|
||||
It "Rows are not changed but header is changed" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value2", @("A1|A2", "B1|B2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
}
|
||||
|
||||
It "Rows are changed and header is changed at the same time" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value", @("A1|A2", "B1|B2")))
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddHeader("MyHeader").AddNode([TableNode]::new("Name|Value2", @("A1|A2", "B1|B2", "C1|C2")))
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 1
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 1
|
||||
|
||||
$comparer.AddedItems[0].PreviousReportNode | Should -BeNullOrEmpty
|
||||
$comparer.AddedItems[0].CurrentReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.AddedItems[0].CurrentReportNode.Headers | Should -Be "Name|Value2"
|
||||
$comparer.AddedItems[0].CurrentReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2", "C1|C2")
|
||||
|
||||
$comparer.DeletedItems[0].PreviousReportNode | Should -BeOfType ([TableNode])
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Headers | Should -Be "Name|Value"
|
||||
$comparer.DeletedItems[0].PreviousReportNode.Rows | Should -BeArray @("A1|A2", "B1|B2")
|
||||
$comparer.DeletedItems[0].CurrentReportNode | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
Describe "NoteNode" {
|
||||
It "NoteNode is ignored from report" {
|
||||
$prevReport = [HeaderNode]::new("Version 1")
|
||||
$prevReport.AddNote("MyFirstNote")
|
||||
$prevReport.AddHeader("MyFirstHeader").AddNote("MyFirstSubNote")
|
||||
|
||||
$nextReport = [HeaderNode]::new("Version 2")
|
||||
$nextReport.AddNote("MySecondNote")
|
||||
$nextReport.AddHeader("MySecondHeader").AddNote("MySecondSubNote")
|
||||
|
||||
$comparer = [SoftwareReportDifferenceCalculator]::new($prevReport, $nextReport)
|
||||
$comparer.CompareReports()
|
||||
|
||||
$comparer.AddedItems | Should -HaveCount 0
|
||||
$comparer.ChangedItems | Should -HaveCount 0
|
||||
$comparer.DeletedItems | Should -HaveCount 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
using module ../SoftwareReport.Nodes.psm1
|
||||
using module ../SoftwareReport.DifferenceRender.psm1
|
||||
|
||||
BeforeDiscovery {
|
||||
Import-Module $(Join-Path $PSScriptRoot "TestHelpers.psm1") -DisableNameChecking
|
||||
}
|
||||
|
||||
Describe "ComparerReport.UnitTests" {
|
||||
BeforeAll {
|
||||
$script:DifferenceRender = [SoftwareReportDifferenceRender]::new()
|
||||
}
|
||||
|
||||
Context "CalculateHtmlTableRowSpan" {
|
||||
It "Without the equal cells" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ Key = "A"; Value = "1" }
|
||||
[PSCustomObject]@{ Key = "B"; Value = "2" }
|
||||
[PSCustomObject]@{ Key = "C"; Value = "3" }
|
||||
)
|
||||
|
||||
$actual = $DifferenceRender.CalculateHtmlTableRowSpan($table, "Key")
|
||||
$actual | Should -BeArray @(1, 1, 1)
|
||||
}
|
||||
|
||||
It "Only equal cells" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ Key = "A"; Value = "D" }
|
||||
[PSCustomObject]@{ Key = "B"; Value = "D" }
|
||||
[PSCustomObject]@{ Key = "C"; Value = "D" }
|
||||
)
|
||||
|
||||
$actual = $DifferenceRender.CalculateHtmlTableRowSpan($table, "Value")
|
||||
$actual | Should -BeArray @(3, 0, 0)
|
||||
}
|
||||
|
||||
It "Single row" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ Key = "A"; Value = "1" }
|
||||
)
|
||||
|
||||
$actual = $DifferenceRender.CalculateHtmlTableRowSpan($table, "Key")
|
||||
$actual | Should -BeArray @(1)
|
||||
}
|
||||
|
||||
It "Different cells" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ Key = "A"; Value = "1" }
|
||||
[PSCustomObject]@{ Key = "B"; Value = "2" }
|
||||
[PSCustomObject]@{ Key = "B"; Value = "3" }
|
||||
[PSCustomObject]@{ Key = "C"; Value = "4" }
|
||||
[PSCustomObject]@{ Key = "C"; Value = "5" }
|
||||
[PSCustomObject]@{ Key = "C"; Value = "6" }
|
||||
[PSCustomObject]@{ Key = "D"; Value = "7" }
|
||||
[PSCustomObject]@{ Key = "E"; Value = "8" }
|
||||
[PSCustomObject]@{ Key = "E"; Value = "9" }
|
||||
[PSCustomObject]@{ Key = "F"; Value = "10" }
|
||||
)
|
||||
|
||||
$actual = $DifferenceRender.CalculateHtmlTableRowSpan($table, "Key")
|
||||
$actual | Should -BeArray @(1, 2, 0, 3, 0, 0, 1, 2, 0, 1)
|
||||
}
|
||||
}
|
||||
|
||||
Context "RenderCategory" {
|
||||
It "With line separator" {
|
||||
$actual = $DifferenceRender.RenderCategory(@("Header 1", "Header 2", "Header 3"), $true)
|
||||
$actual | Should -Be "Header 2 ><br> Header 3"
|
||||
}
|
||||
|
||||
It "Without line separator" {
|
||||
$actual = $DifferenceRender.RenderCategory(@("Header 1", "Header 2", "Header 3"), $false)
|
||||
$actual | Should -Be "Header 2 > Header 3"
|
||||
}
|
||||
|
||||
It "One header" {
|
||||
$actual = $DifferenceRender.RenderCategory(@("Header 1"), $false)
|
||||
$actual | Should -Be ""
|
||||
}
|
||||
|
||||
It "Empty headers" {
|
||||
$actual = $DifferenceRender.RenderCategory(@(), $false)
|
||||
$actual | Should -Be ""
|
||||
}
|
||||
}
|
||||
|
||||
Context "RenderToolName" {
|
||||
It "Clear tool name" {
|
||||
$actual = $DifferenceRender.RenderToolName("My Tool 1")
|
||||
$actual | Should -Be "My Tool 1"
|
||||
}
|
||||
|
||||
It "Name with colon symbol" {
|
||||
$actual = $DifferenceRender.RenderToolName("My Tool 1:")
|
||||
$actual | Should -Be "My Tool 1"
|
||||
}
|
||||
}
|
||||
|
||||
Context "StrikeTableRow" {
|
||||
It "Simple row" {
|
||||
$actual = $DifferenceRender.StrikeTableRow("Test1|Test2|Test3")
|
||||
$actual | Should -Be "~~Test1~~|~~Test2~~|~~Test3~~"
|
||||
}
|
||||
|
||||
It "Row with spaces" {
|
||||
$actual = $DifferenceRender.StrikeTableRow("Test 1|Test 2|Test 3")
|
||||
$actual | Should -Be "~~Test 1~~|~~Test 2~~|~~Test 3~~"
|
||||
}
|
||||
}
|
||||
|
||||
Context "RenderHtmlTable" {
|
||||
It "Simple table" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ "Category" = "A"; "Tool name" = "My Tool 1"; "Version" = "1.0" },
|
||||
[PSCustomObject]@{ "Category" = "B"; "Tool name" = "My Tool 2"; "Version" = "2.0" },
|
||||
[PSCustomObject]@{ "Category" = "C"; "Tool name" = "My Tool 3"; "Version" = "3.0" }
|
||||
)
|
||||
|
||||
$renderedTable = $DifferenceRender.RenderHtmlTable($table, "Category")
|
||||
$renderedTable | Should -Be @'
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Version</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1">A</td>
|
||||
<td>My Tool 1</td>
|
||||
<td>1.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">B</td>
|
||||
<td>My Tool 2</td>
|
||||
<td>2.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">C</td>
|
||||
<td>My Tool 3</td>
|
||||
<td>3.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
'@
|
||||
|
||||
}
|
||||
|
||||
It "Table with the same category" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{ "Category" = "A"; "Tool name" = "My Tool 1"; "Version" = "1.0" },
|
||||
[PSCustomObject]@{ "Category" = "A"; "Tool name" = "My Tool 2"; "Version" = "2.0" },
|
||||
[PSCustomObject]@{ "Category" = "A"; "Tool name" = "My Tool 3"; "Version" = "3.0" },
|
||||
[PSCustomObject]@{ "Category" = "B"; "Tool name" = "My Tool 4"; "Version" = "4.0" }
|
||||
)
|
||||
|
||||
$renderedTable = $DifferenceRender.RenderHtmlTable($table, "Category")
|
||||
$renderedTable | Should -Be @'
|
||||
<table>
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Tool name</th>
|
||||
<th>Version</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">A</td>
|
||||
<td>My Tool 1</td>
|
||||
<td>1.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>My Tool 2</td>
|
||||
<td>2.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>My Tool 3</td>
|
||||
<td>3.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">B</td>
|
||||
<td>My Tool 4</td>
|
||||
<td>4.0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
'@
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Context "RenderTableNodesDiff" {
|
||||
It "Add new table" {
|
||||
$previousNode = $null
|
||||
$currentNode = [TableNode]::new("Name|Value", @("A|1", "B|2"))
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ---- | ----- |
|
||||
| A | 1 |
|
||||
| B | 2 |
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Remove existing table" {
|
||||
$previousNode = [TableNode]::new("Name|Value", @("A|1", "B|2"))
|
||||
$currentNode = $null
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| ~~A~~ | ~~1~~ |
|
||||
| ~~B~~ | ~~2~~ |
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Add new rows to existing table" {
|
||||
$previousNode = [TableNode]::new("Name|Value", @("A|1", "B|2"))
|
||||
$currentNode = [TableNode]::new("Name|Value", @("A|1", "B|2", "C|3", "D|4"))
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ---- | ----- |
|
||||
| C | 3 |
|
||||
| D | 4 |
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Remove rows from existing table" {
|
||||
$previousNode = [TableNode]::new("Name|Value", @("A|1", "B|2", "C|3", "D|4"))
|
||||
$currentNode = [TableNode]::new("Name|Value", @("C|3", "D|4"))
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| ~~A~~ | ~~1~~ |
|
||||
| ~~B~~ | ~~2~~ |
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Row is changed in existing table" {
|
||||
$previousNode = [TableNode]::new("Name|Value", @("A|1", "B|2"))
|
||||
$currentNode = [TableNode]::new("Name|Value", @("A|1", "B|3"))
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| ~~B~~ | ~~2~~ |
|
||||
| B | 3 |
|
||||
|
||||
'@
|
||||
}
|
||||
|
||||
It "Row is changed, added and removed at the same time in existing table" {
|
||||
$previousNode = [TableNode]::new("Name|Value", @("A|1", "B|2", "C|3", "D|4"))
|
||||
$currentNode = [TableNode]::new("Name|Value", @("B|2", "C|4", "D|4", "E|5"))
|
||||
$reportItem = [ReportDifferenceItem]::new($previousNode, $currentNode, @("Header 1", "Header 2", "Header 3"))
|
||||
|
||||
$actual = $DifferenceRender.RenderTableNodesDiff($reportItem)
|
||||
$actual | Should -Be @'
|
||||
#### Header 2 > Header 3
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| ~~A~~ | ~~1~~ |
|
||||
| ~~C~~ | ~~3~~ |
|
||||
| C | 4 |
|
||||
| E | 5 |
|
||||
|
||||
'@
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using module ../SoftwareReport.psm1
|
||||
using module ../SoftwareReport.Nodes.psm1
|
||||
|
||||
Describe "SoftwareReport.E2E" {
|
||||
Context "Report example 1" {
|
||||
BeforeEach {
|
||||
$softwareReport = [SoftwareReport]::new("macOS 11")
|
||||
$softwareReport.Root.AddToolVersion("OS Version:", "macOS 11.7 (20G817)")
|
||||
$softwareReport.Root.AddToolVersion("Image Version:", "20220918.1")
|
||||
$installedSoftware = $softwareReport.Root.AddHeader("Installed Software")
|
||||
|
||||
$languagesAndRuntimes = $installedSoftware.AddHeader("Language and Runtime")
|
||||
$languagesAndRuntimes.AddToolVersion("Bash", "5.1.16(1)-release")
|
||||
$languagesAndRuntimes.AddToolVersionsListInline(".NET Core SDK", @("1.2.100", "1.2.200", "3.1.414"), "^\d+\.\d+\.\d")
|
||||
$languagesAndRuntimes.AddNode([ToolVersionNode]::new("Perl", "5.34.0"))
|
||||
|
||||
$cachedTools = $installedSoftware.AddHeader("Cached Tools")
|
||||
$cachedTools.AddToolVersionsList("Ruby", @("2.7.3", "2.8.1", "3.1.2"), "^\d+\.\d+")
|
||||
$cachedTools.AddToolVersionsList("Node.js", @("14.8.0", "15.1.0", "16.4.2"), "^\d+")
|
||||
|
||||
$javaSection = $installedSoftware.AddHeader("Java")
|
||||
$javaSection.AddTable(@(
|
||||
[PSCustomObject] @{ Version = "8.0.125"; Vendor = "My Vendor"; "Environment Variable" = "JAVA_HOME_8_X64" },
|
||||
[PSCustomObject] @{ Version = "11.3.103"; Vendor = "My Vendor"; "Environment Variable" = "JAVA_HOME_11_X64" }
|
||||
))
|
||||
|
||||
$sqlSection = $installedSoftware.AddHeader("MySQL")
|
||||
$sqlSection.AddToolVersion("MySQL", "6.1.0")
|
||||
$sqlSection.AddNote("MySQL service is disabled by default.`nUse the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'")
|
||||
|
||||
$expectedMarkdown = @'
|
||||
# macOS 11
|
||||
- OS Version: macOS 11.7 (20G817)
|
||||
- Image Version: 20220918.1
|
||||
|
||||
## Installed Software
|
||||
|
||||
### Language and Runtime
|
||||
- Bash 5.1.16(1)-release
|
||||
- .NET Core SDK: 1.2.100, 1.2.200, 3.1.414
|
||||
- Perl 5.34.0
|
||||
|
||||
### Cached Tools
|
||||
|
||||
#### Ruby
|
||||
- 2.7.3
|
||||
- 2.8.1
|
||||
- 3.1.2
|
||||
|
||||
#### Node.js
|
||||
- 14.8.0
|
||||
- 15.1.0
|
||||
- 16.4.2
|
||||
|
||||
### Java
|
||||
| Version | Vendor | Environment Variable |
|
||||
| -------- | --------- | -------------------- |
|
||||
| 8.0.125 | My Vendor | JAVA_HOME_8_X64 |
|
||||
| 11.3.103 | My Vendor | JAVA_HOME_11_X64 |
|
||||
|
||||
### MySQL
|
||||
- MySQL 6.1.0
|
||||
```
|
||||
MySQL service is disabled by default.
|
||||
Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'
|
||||
```
|
||||
'@
|
||||
}
|
||||
|
||||
It "ToMarkdown" {
|
||||
$softwareReport.ToMarkdown() | Should -Be $expectedMarkdown
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$json = $softwareReport.ToJson()
|
||||
$deserializedReport = [SoftwareReport]::FromJson($json)
|
||||
$deserializedReport.ToMarkdown() | Should -Be $expectedMarkdown
|
||||
}
|
||||
}
|
||||
|
||||
Context "GetImageVersion" {
|
||||
It "Image version exists" {
|
||||
$softwareReport = [SoftwareReport]::new("MyReport")
|
||||
$softwareReport.Root.AddToolVersion("Image Version:", "123.4")
|
||||
$softwareReport.GetImageVersion() | Should -Be "123.4"
|
||||
}
|
||||
|
||||
It "Empty report" {
|
||||
$softwareReport = [SoftwareReport]::new("MyReport")
|
||||
$softwareReport.GetImageVersion() | Should -Be "Unknown version"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
using module ../SoftwareReport.Nodes.psm1
|
||||
|
||||
BeforeDiscovery {
|
||||
Import-Module $(Join-Path $PSScriptRoot "TestHelpers.psm1") -DisableNameChecking
|
||||
}
|
||||
|
||||
Describe "Nodes.UnitTests" {
|
||||
Context "ToolVersionNode" {
|
||||
It "ToMarkdown" {
|
||||
$node = [ToolVersionNode]::new("MyTool", "2.1.3")
|
||||
$node.ToMarkdown() | Should -Be "- MyTool 2.1.3"
|
||||
}
|
||||
|
||||
It "GetValue" {
|
||||
$node = [ToolVersionNode]::new("MyTool", "2.1.3")
|
||||
$node.GetValue() | Should -Be "2.1.3"
|
||||
}
|
||||
|
||||
It "Serialization" {
|
||||
$node = [ToolVersionNode]::new("MyTool", "2.1.3")
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "ToolVersionNode"
|
||||
$json.ToolName | Should -Be "MyTool"
|
||||
$json.Version | Should -Be "2.1.3"
|
||||
}
|
||||
|
||||
It "Deserialization" {
|
||||
{ [ToolVersionNode]::FromJsonObject(@{ NodeType = "ToolVersionNode"; ToolName = ""; Version = "2.1.3" }) } | Should -Throw '*Exception setting "ToolName": "The argument is null or empty.*'
|
||||
{ [ToolVersionNode]::FromJsonObject(@{ NodeType = "ToolVersionNode"; ToolName = "MyTool"; Version = "" }) } | Should -Throw '*Exception setting "Version": "The argument is null or empty.*'
|
||||
{ [ToolVersionNode]::FromJsonObject(@{ NodeType = "ToolVersionNode"; ToolName = "MyTool"; Version = "2.1.3" }) } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$node = [ToolVersionNode]::new("MyTool", "2.1.3")
|
||||
$json = $node.ToJsonObject()
|
||||
$node2 = [ToolVersionNode]::FromJsonObject($json)
|
||||
$json2 = $node2.ToJsonObject()
|
||||
$($json | ConvertTo-Json) | Should -Be $($json2 | ConvertTo-Json)
|
||||
}
|
||||
|
||||
It "IsSimilarTo" {
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsSimilarTo([ToolVersionNode]::new("MyTool", "2.1.3")) | Should -BeTrue
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsSimilarTo([ToolVersionNode]::new("MyTool", "1.0.0")) | Should -BeTrue
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsSimilarTo([ToolVersionNode]::new("MyTool2", "2.1.3")) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "IsIdenticalTo" {
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsIdenticalTo([ToolVersionNode]::new("MyTool", "2.1.3")) | Should -BeTrue
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsIdenticalTo([ToolVersionNode]::new("MyTool", "1.0.0")) | Should -BeFalse
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3").IsIdenticalTo([ToolVersionNode]::new("MyTool2", "2.1.3")) | Should -BeFalse
|
||||
}
|
||||
}
|
||||
|
||||
Context "ToolVersionsListNode" {
|
||||
It "ToMarkdown - List" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "List")
|
||||
$expected = @(
|
||||
"",
|
||||
"# MyTool"
|
||||
"- 2.7.7"
|
||||
"- 3.0.5"
|
||||
"- 3.1.3"
|
||||
) -join "`n"
|
||||
$node.ToMarkdown() | Should -Be $expected
|
||||
}
|
||||
|
||||
It "ToMarkdown - Inline" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "Inline")
|
||||
$node.ToMarkdown() | Should -Be "- MyTool: 2.7.7, 3.0.5, 3.1.3"
|
||||
}
|
||||
|
||||
It "GetValue" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "List")
|
||||
$node.GetValue() | Should -Be "2.7.7, 3.0.5, 3.1.3"
|
||||
}
|
||||
|
||||
It "Serialization - List" {
|
||||
$node = [ToolVersionsListNode]::new("Ruby", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "List")
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "ToolVersionsListNode"
|
||||
$json.ToolName | Should -Be "Ruby"
|
||||
$json.Versions | Should -BeArray @("2.7.7", "3.0.5", "3.1.3")
|
||||
$json.MajorVersionRegex | Should -Be "^.+"
|
||||
$json.ListType | Should -Be "List"
|
||||
}
|
||||
|
||||
It "Serialization - Inline" {
|
||||
$node = [ToolVersionsListNode]::new("Ruby", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "Inline")
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "ToolVersionsListNode"
|
||||
$json.ToolName | Should -Be "Ruby"
|
||||
$json.Versions | Should -BeArray @("2.7.7", "3.0.5", "3.1.3")
|
||||
$json.MajorVersionRegex | Should -Be "^.+"
|
||||
$json.ListType | Should -Be "Inline"
|
||||
}
|
||||
|
||||
It "Deserialization" {
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = ""; Versions = @("2.1.3", "3.1.4"); MajorVersionRegex = "^\d+"; ListType = "List" }) } | Should -Throw '*Exception setting "ToolName": "The argument is null or empty.*'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; MajorVersionRegex = "^\d+"; ListType = "List" }) } | Should -Throw '*Exception setting "Versions": "The argument is null or empty.*'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @(); MajorVersionRegex = "^\d+"; ListType = "List" }) } | Should -Throw '*Exception setting "Versions": "The argument is null, empty,*'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @("2.1.3", '2.2.4'); MajorVersionRegex = "^\d+"; ListType = "List" }) } | Should -Throw 'Multiple versions from list * return the same result from regex *'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @("2.1.3", "3.1.4"); MajorVersionRegex = ""; ListType = "List" }) } | Should -Throw 'Version * doesn''t match regex *'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @("2.1.3", "3.1.4"); MajorVersionRegex = "^\d+"; ListType = "Fake" }) } | Should -Throw '*Exception setting "ListType": "The argument * does not belong to the set*'
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @("2.1.3", "3.1.4"); MajorVersionRegex = "^\d+"; ListType = "List" }) } | Should -Not -Throw
|
||||
{ [ToolVersionsListNode]::FromJsonObject(@{ NodeType = "ToolVersionsListNode"; ToolName = "MyTool"; Versions = @("2.1.3", "3.1.4"); MajorVersionRegex = "^\d+"; ListType = "Inline" }) } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$node = [ToolVersionsListNode]::new("Ruby", @("2.7.7", "3.0.5", "3.1.3"), "^.+", "List")
|
||||
$json = $node.ToJsonObject()
|
||||
$node2 = [ToolVersionsListNode]::FromJsonObject($json)
|
||||
$json2 = $node2.ToJsonObject()
|
||||
$($json | ConvertTo-Json) | Should -Be $($json2 | ConvertTo-Json)
|
||||
}
|
||||
|
||||
It "IsSimilarTo" {
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsSimilarTo(
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List")
|
||||
) | Should -BeTrue
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsSimilarTo(
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.5", "5.0.0"), "^.+", "List")
|
||||
) | Should -BeTrue
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsSimilarTo(
|
||||
[ToolVersionsListNode]::new("MyTool2", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List")
|
||||
) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "IsIdenticalTo" {
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsIdenticalTo(
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List")
|
||||
) | Should -BeTrue
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsIdenticalTo(
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.5", "5.0.0"), "^.+", "List")
|
||||
) | Should -BeFalse
|
||||
[ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List").IsIdenticalTo(
|
||||
[ToolVersionsListNode]::new("MyTool2", @("2.1.3", "3.1.5", "4.0.0"), "^.+", "List")
|
||||
) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "ExtractMajorVersion" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^\d+\.\d+", "List")
|
||||
$node.ExtractMajorVersion("2.1.3") | Should -Be "2.1"
|
||||
$node.ExtractMajorVersion("3.1.5") | Should -Be "3.1"
|
||||
$node.ExtractMajorVersion("4.0.0") | Should -Be "4.0"
|
||||
}
|
||||
|
||||
Context "ValidateMajorVersionRegex" {
|
||||
It "Major version regex - unique versions" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "4.0.0"), "^\d+", "List")
|
||||
$node.Versions | Should -BeArray @("2.1.3", "3.1.5", "4.0.0")
|
||||
}
|
||||
|
||||
It "Major version regex - non-unique versions" {
|
||||
{ [ToolVersionsListNode]::new("MyTool", @("2.1.3", "3.1.5", "3.2.0", "4.0.0"), "^\d+", "List") } | Should -Throw "Multiple versions from list * return the same result from regex *"
|
||||
}
|
||||
|
||||
It "Minor version regex - unique versions" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.1.3", "2.4.0", "3.1.2"), "^\d+\.\d+", "List")
|
||||
$node.Versions | Should -BeArray @("2.1.3", "2.4.0", "3.1.2")
|
||||
}
|
||||
|
||||
It "Minor version regex - non-unique versions" {
|
||||
{ [ToolVersionsListNode]::new("MyTool", @("2.1.3", "2.1.4", "3.1.2"), "^\d+\.\d+", "List") } | Should -Throw "Multiple versions from list * return the same result from regex *"
|
||||
}
|
||||
|
||||
It "Patch version regex - unique versions" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.1.3", "2.1.4", "2.1.5"), "^\d+\.\d+\.\d+", "List")
|
||||
$node.Versions | Should -BeArray @("2.1.3", "2.1.4", "2.1.5")
|
||||
}
|
||||
|
||||
It "Patch version regex - non-unique versions" {
|
||||
{ [ToolVersionsListNode]::new("MyTool", @("2.1.3", "2.1.4", "2.1.4"), "^\d+\.\d+\.\d+", "List") } | Should -Throw "Multiple versions from list * return the same result from regex *"
|
||||
}
|
||||
|
||||
It ".NET Core version regex - unique versions" {
|
||||
$node = [ToolVersionsListNode]::new("MyTool", @("2.1.100", "2.1.205", "2.1.303"), "^\d+\.\d+\.\d", "List")
|
||||
$node.Versions | Should -BeArray @("2.1.100", "2.1.205", "2.1.303")
|
||||
}
|
||||
|
||||
It ".NET Core version regex - non-unique versions" {
|
||||
{ [ToolVersionsListNode]::new("MyTool", @("2.1.100", "2.1.205", "2.1.230", "3.1.0"), "^\d+\.\d+\.\d", "List") } | Should -Throw "Multiple versions from list * return the same result from regex *"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "TableNode" {
|
||||
It "ToMarkdown (Simple table)" {
|
||||
$node = [TableNode]::new("Name|Value", @("A|B", "C|D"))
|
||||
$node.ToMarkdown() | Should -Be @'
|
||||
| Name | Value |
|
||||
| ---- | ----- |
|
||||
| A | B |
|
||||
| C | D |
|
||||
'@
|
||||
}
|
||||
|
||||
It "ToMarkdown (Wide cells)" {
|
||||
$node = [TableNode]::new("Name|Value", @("Very long value here|B", "C|And very long value here too"))
|
||||
$node.ToMarkdown() | Should -Be @'
|
||||
| Name | Value |
|
||||
| -------------------- | ---------------------------- |
|
||||
| Very long value here | B |
|
||||
| C | And very long value here too |
|
||||
'@
|
||||
}
|
||||
|
||||
It "CalculateColumnsWidth" {
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).CalculateColumnsWidth() | Should -BeArray @(4, 5)
|
||||
[TableNode]::new("Name|Value", @("Very long value here|B", "C|And very long value here too")).CalculateColumnsWidth() | Should -BeArray @(20, 28)
|
||||
}
|
||||
|
||||
It "Serialization" {
|
||||
$node = [TableNode]::new("Name|Value", @("A|B", "C|D"))
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "TableNode"
|
||||
$json.Headers | Should -Be "Name|Value"
|
||||
$json.Rows | Should -BeArray @("A|B", "C|D")
|
||||
}
|
||||
|
||||
It "Deserialization" {
|
||||
{ [TableNode]::FromJsonObject(@{ NodeType = "TableNode"; Headers = ""; Rows = @("A|1", "B|2") }) } | Should -Throw 'Exception setting "Headers": "The argument is null or empty. *'
|
||||
{ [TableNode]::FromJsonObject(@{ NodeType = "TableNode"; Headers = "Name|Value"; Rows = @() }) } | Should -Throw 'Exception setting "Rows": "The argument is null, empty, *'
|
||||
{ [TableNode]::FromJsonObject(@{ NodeType = "TableNode"; Headers = "Name|Value"; Rows = @("A|1", "B|2|T", "C|3") }) } | Should -Throw 'Table has different number of columns in different rows'
|
||||
{ [TableNode]::FromJsonObject(@{ NodeType = "TableNode"; Headers = "Name|Value"; Rows = @("A|1", "B|2") }) } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$node = [TableNode]::new("Name|Value", @("A|B", "C|D"))
|
||||
$json = $node.ToJsonObject()
|
||||
$node2 = [TableNode]::FromJsonObject($json)
|
||||
$json2 = $node2.ToJsonObject()
|
||||
$($json | ConvertTo-Json) | Should -Be $($json2 | ConvertTo-Json)
|
||||
}
|
||||
|
||||
It "IsSimilarTo" {
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsSimilarTo([TableNode]::new("Name|Value", @("A|B", "C|D"))) | Should -BeTrue
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsSimilarTo([TableNode]::new("Name|Value", @("A|B", "C|D", "F|W"))) | Should -BeTrue
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsSimilarTo([TableNode]::new("Name|Value", @("A|B", "C|E"))) | Should -BeTrue
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsSimilarTo([TableNode]::new("Name|Key", @("A|B", "C|D"))) | Should -BeTrue
|
||||
}
|
||||
|
||||
It "IsIdenticalTo" {
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsIdenticalTo([TableNode]::new("Name|Value", @("A|B", "C|D"))) | Should -BeTrue
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsIdenticalTo([TableNode]::new("Name|Key", @("A|B", "C|D"))) | Should -BeTrue
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsIdenticalTo([TableNode]::new("Name|Value", @("A|B", "C|D", "F|W"))) | Should -BeFalse
|
||||
[TableNode]::new("Name|Value", @("A|B", "C|D")).IsIdenticalTo([TableNode]::new("Name|Value", @("A|B", "C|E"))) | Should -BeFalse
|
||||
}
|
||||
|
||||
Context "FromObjectsArray" {
|
||||
It "Correct table" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{Name = "A"; Value = "B"}
|
||||
[PSCustomObject]@{Name = "C"; Value = "D"}
|
||||
)
|
||||
|
||||
$tableNode = [TableNode]::FromObjectsArray($table)
|
||||
$tableNode.Headers | Should -Be "Name|Value"
|
||||
$tableNode.Rows | Should -BeArray @("A|B", "C|D")
|
||||
}
|
||||
|
||||
It "Correct table with spaces" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{Name = "A B"; "My Value" = "1 2"}
|
||||
[PSCustomObject]@{Name = "C D"; "My Value" = "3 4"}
|
||||
)
|
||||
|
||||
$tableNode = [TableNode]::FromObjectsArray($table)
|
||||
$tableNode.Headers | Should -Be "Name|My Value"
|
||||
$tableNode.Rows | Should -BeArray @("A B|1 2", "C D|3 4")
|
||||
}
|
||||
|
||||
It "Throw on empty table" {
|
||||
{ [TableNode]::FromObjectsArray(@()) } | Should -Throw "Failed to create TableNode from empty objects array"
|
||||
}
|
||||
|
||||
It "Throw on table with different columns" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{Name = "A"; Value = "B"}
|
||||
[PSCustomObject]@{Name = "C"; Value2 = "D"}
|
||||
)
|
||||
|
||||
{ [TableNode]::FromObjectsArray($table) } | Should -Throw "Failed to create TableNode from objects array because objects have different properties"
|
||||
}
|
||||
|
||||
It "Throw on empty row" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{Name = "A"; Value = "B"},
|
||||
[PSCustomObject]@{},
|
||||
[PSCustomObject]@{Name = "C"; Value2 = "D"}
|
||||
)
|
||||
|
||||
{ [TableNode]::FromObjectsArray($table) } | Should -Throw "Failed to create TableNode because some objects are empty"
|
||||
}
|
||||
|
||||
It "Throw on incorrect symbols in table column names" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{"Name|War" = "A"; Value = "B"}
|
||||
[PSCustomObject]@{"Name|War" = "C"; Value = "D"}
|
||||
)
|
||||
|
||||
{ [TableNode]::FromObjectsArray($table) } | Should -Throw "Failed to create TableNode because some cells * contains forbidden symbol*"
|
||||
}
|
||||
|
||||
It "Throw on incorrect symbols in table rows" {
|
||||
$table = @(
|
||||
[PSCustomObject]@{Name = "A"; Value = "B|AA"}
|
||||
[PSCustomObject]@{Name = "C"; Value = "D"}
|
||||
)
|
||||
|
||||
{ [TableNode]::FromObjectsArray($table) } | Should -Throw "Failed to create TableNode because some cells * contains forbidden symbol*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "NoteNode" {
|
||||
It "ToMarkdown" {
|
||||
$node = [NoteNode]::new("Hello world`nGood Bye world")
|
||||
$node.ToMarkdown() | Should -Be @'
|
||||
```
|
||||
hello world
|
||||
Good Bye world
|
||||
```
|
||||
'@
|
||||
}
|
||||
|
||||
It "Serialization" {
|
||||
$node = [NoteNode]::new("MyContent`nMyContent2")
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "NoteNode"
|
||||
$json.Content | Should -Be "MyContent`nMyContent2"
|
||||
}
|
||||
|
||||
It "Deserialization" {
|
||||
{ [NoteNode]::FromJsonObject(@{ NodeType = "NoteNode" }) } | Should -Throw '*Exception setting "Content": "The argument is null or empty.*'
|
||||
{ [NoteNode]::FromJsonObject(@{ NodeType = "NoteNode"; Content = "" }) } | Should -Throw '*Exception setting "Content": "The argument is null or empty.*'
|
||||
{ [NoteNode]::FromJsonObject(@{ NodeType = "NoteNode"; Content = "MyTool" }) } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$node = [NoteNode]::new("MyContent`nMyContent2")
|
||||
$json = $node.ToJsonObject()
|
||||
$node2 = [NoteNode]::FromJsonObject($json)
|
||||
$json2 = $node2.ToJsonObject()
|
||||
$($json | ConvertTo-Json) | Should -Be $($json2 | ConvertTo-Json)
|
||||
}
|
||||
|
||||
It "IsSimilarTo" {
|
||||
[NoteNode]::new("MyContent").IsSimilarTo([NoteNode]::new("MyContent")) | Should -BeTrue
|
||||
[NoteNode]::new("MyContent").IsSimilarTo([NoteNode]::new("MyContent2")) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "IsIdenticalTo" {
|
||||
[NoteNode]::new("MyContent").IsIdenticalTo([NoteNode]::new("MyContent")) | Should -BeTrue
|
||||
[NoteNode]::new("MyContent").IsIdenticalTo([NoteNode]::new("MyContent2")) | Should -BeFalse
|
||||
}
|
||||
}
|
||||
|
||||
Context "HeaderNode" {
|
||||
It "ToMarkdown" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
$node.ToMarkdown(1) | Should -Be @'
|
||||
|
||||
# MyHeader
|
||||
- MyTool 2.1.3
|
||||
'@
|
||||
}
|
||||
|
||||
It "ToMarkdown (level 3)" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
$node.ToMarkdown(3) | Should -Be @'
|
||||
|
||||
### MyHeader
|
||||
- MyTool 2.1.3
|
||||
'@
|
||||
}
|
||||
|
||||
It "ToMarkdown (multiple levels)" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddHeader("MyHeader 2").AddHeader("MyHeader 3").AddHeader("MyHeader 4").AddToolVersion("MyTool", "2.1.3")
|
||||
$node.ToMarkdown(1) | Should -Be @'
|
||||
|
||||
# MyHeader
|
||||
|
||||
## MyHeader 2
|
||||
|
||||
### MyHeader 3
|
||||
|
||||
#### MyHeader 4
|
||||
- MyTool 2.1.3
|
||||
'@
|
||||
}
|
||||
|
||||
It "Serialization" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
$json = $node.ToJsonObject()
|
||||
$json.NodeType | Should -Be "HeaderNode"
|
||||
$json.Title | Should -Be "MyHeader"
|
||||
$json.Children | Should -HaveCount 1
|
||||
}
|
||||
|
||||
It "Deserialization" {
|
||||
{ [HeaderNode]::FromJsonObject(@{ NodeType = "HeaderNode" }) } | Should -Throw '*Exception setting "Title": "The argument is null or empty.*'
|
||||
{ [HeaderNode]::FromJsonObject(@{ NodeType = "HeaderNode"; Title = "" }) } | Should -Throw '*Exception setting "Title": "The argument is null or empty.*'
|
||||
{ [HeaderNode]::FromJsonObject(@{ NodeType = "HeaderNode"; Title = "MyHeader" }) } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Serialization + Deserialization" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
$json = $node.ToJsonObject()
|
||||
$node2 = [HeaderNode]::FromJsonObject($json)
|
||||
$json2 = $node2.ToJsonObject()
|
||||
$($json | ConvertTo-Json) | Should -Be $($json2 | ConvertTo-Json)
|
||||
}
|
||||
|
||||
It "IsSimilarTo" {
|
||||
[HeaderNode]::new("MyHeader").IsSimilarTo([HeaderNode]::new("MyHeader")) | Should -BeTrue
|
||||
[HeaderNode]::new("MyHeader").IsSimilarTo([HeaderNode]::new("MyHeader2")) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "IsIdenticalTo" {
|
||||
[HeaderNode]::new("MyHeader").IsIdenticalTo([HeaderNode]::new("MyHeader")) | Should -BeTrue
|
||||
[HeaderNode]::new("MyHeader").IsIdenticalTo([HeaderNode]::new("MyHeader2")) | Should -BeFalse
|
||||
}
|
||||
|
||||
It "FindSimilarChildNode" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
|
||||
$node.FindSimilarChildNode([ToolVersionNode]::new("MyTool", "1.0.0")) | Should -Not -BeNullOrEmpty
|
||||
$node.FindSimilarChildNode([ToolVersionNode]::New("MyTool2", "1.0.0")) | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
Context "Detect node duplicates" {
|
||||
It "Similar HeaderNode on the same header" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddHeader("MySubHeader1")
|
||||
$node.AddHeader("MySubHeader2")
|
||||
{ $node.AddHeader("MySubHeader1") } | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "Similar ToolVersionNode on the same header" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersion("MyTool", "2.1.3")
|
||||
$node.AddToolVersion("MyTool2", "2.1.3")
|
||||
{ $node.AddToolVersion("MyTool", "2.1.3") } | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "Similar ToolVersionsListNode on the same header" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddToolVersionsListInline("MyTool", @("2.1.3", "3.0.0"), "^\d+")
|
||||
$node.AddToolVersionsListInline("MyTool2", @("2.1.3", "3.0.0"), "^\d+")
|
||||
{ $node.AddToolVersionsList("MyTool", @("2.1.3", "3.0.0"), "^\d+") } | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "Similar TableNode on the same header" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddTable(@(
|
||||
[PSCustomObject]@{Name = "Value1"},
|
||||
[PSCustomObject]@{Name = "Value2"}
|
||||
))
|
||||
{
|
||||
$node.AddTable(@(
|
||||
[PSCustomObject]@{Name = "Value1"},
|
||||
[PSCustomObject]@{Name = "Value2"}
|
||||
))
|
||||
} | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "Similar NoteNode on the same header" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddNote("MyContent")
|
||||
$node.AddNote("MyContent2")
|
||||
{ $node.AddNote("MyContent") } | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "AddNode detects duplicates" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddNode([ToolVersionNode]::new("MyTool", "2.1.3"))
|
||||
{ $node.AddNode([ToolVersionNode]::new("MyTool", "2.1.3")) } | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "AddNodes detects duplicates" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
$node.AddNodes(@(
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3"),
|
||||
[ToolVersionNode]::new("MyTool2", "2.1.4")
|
||||
))
|
||||
{
|
||||
$node.AddNodes(@(
|
||||
[ToolVersionNode]::new("MyTool3", "2.1.5"),
|
||||
[ToolVersionNode]::new("MyTool", "2.1.3")
|
||||
))
|
||||
} | Should -Throw "This HeaderNode already contains the similar child node. It is not allowed to add the same node twice.*"
|
||||
}
|
||||
|
||||
It "Doesn't allow adding non-header nodes after header node" {
|
||||
$node = [HeaderNode]::new("MyHeader")
|
||||
{ $node.AddToolVersion("MyTool", "2.1.3") } | Should -Not -Throw
|
||||
{ $node.AddHeader("MySubHeader") } | Should -Not -Throw
|
||||
{ $node.AddToolVersion("MyTool2", "2.1.4") } | Should -Throw "It is not allowed to add the non-header node after the header node. Consider adding the separate HeaderNode for this node"
|
||||
{ $node.AddHeader("MySubHeader2") } | Should -Not -Throw
|
||||
{ $node.AddToolVersionsListInline("MyTool3", @("2.1.4", "2.1.5"), "^.+") } | Should -Throw "It is not allowed to add the non-header node after the header node. Consider adding the separate HeaderNode for this node"
|
||||
{ $node.AddToolVersionsList("MyTool4", @("2.1.4", "2.1.5"), "^.+") } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
function ShouldBeArray([Array] $ActualValue, [Array]$ExpectedValue, [Switch] $Negate, [String] $Because) {
|
||||
if ($Negate) {
|
||||
throw "Negation is not supported for Should-BeArray"
|
||||
}
|
||||
|
||||
if ($ExpectedValue.Count -eq 0) {
|
||||
throw "Expected array cannot be empty. Use Should-BeNullOrEmpty instead."
|
||||
}
|
||||
|
||||
$ExpectedValue | ForEach-Object {
|
||||
if ($_.GetType() -notin @([String], [Int32])) {
|
||||
throw "Only string or int arrays are supported in Should-BeArray"
|
||||
}
|
||||
}
|
||||
|
||||
$actualValueJson = $ActualValue | ConvertTo-Json
|
||||
$expectedValueJson = $ExpectedValue | ConvertTo-Json
|
||||
|
||||
$succeeded = ($ActualValue.Count -eq $ExpectedValue.Count) -and ($actualValueJson -eq $expectedValueJson)
|
||||
|
||||
if (-not $succeeded) {
|
||||
$failureMessage = "Expected array '$actualValueJson' to be equal to '$expectedValueJson'"
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
Succeeded = $succeeded
|
||||
FailureMessage = $failureMessage
|
||||
}
|
||||
}
|
||||
|
||||
Add-ShouldOperator -Name BeArray `
|
||||
-InternalName 'ShouldBeArray' `
|
||||
-Test ${function:ShouldBeArray} `
|
||||
-SupportsArrayInput
|
||||
@@ -4,16 +4,46 @@
|
||||
# - https://github.community/t5/GitHub-Actions/GitHub-Actions-Manual-Trigger-Approvals/td-p/31504
|
||||
# - https://github.community/t5/GitHub-Actions/Protecting-github-workflows/td-p/30290
|
||||
|
||||
parameters:
|
||||
- name: job_id
|
||||
type: string
|
||||
default: 'generate_image'
|
||||
|
||||
- name: image_type
|
||||
type: string
|
||||
|
||||
- name: image_readme_name
|
||||
type: string
|
||||
|
||||
- name: agent_pool
|
||||
type: object
|
||||
default:
|
||||
name: 'ci-agent-pool'
|
||||
|
||||
- name: variable_group_name
|
||||
type: string
|
||||
default: 'Image Generation Variables'
|
||||
|
||||
- name: create_release
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
- name: repository_ref
|
||||
type: string
|
||||
default: 'self'
|
||||
|
||||
jobs:
|
||||
- job:
|
||||
- job: ${{ parameters.job_id }}
|
||||
displayName: Image Generation (${{ parameters.image_type }})
|
||||
timeoutInMinutes: 600
|
||||
cancelTimeoutInMinutes: 30
|
||||
pool: ci-agent-pool
|
||||
pool: ${{ parameters.agent_pool }}
|
||||
variables:
|
||||
- group: Image Generation Variables
|
||||
- group: ${{ parameters.variable_group_name }}
|
||||
|
||||
steps:
|
||||
- checkout: ${{ parameters.repository_ref }}
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Download custom repository'
|
||||
condition: and(ne(variables['CUSTOM_REPOSITORY_URL'], ''), ne(variables['CUSTOM_REPOSITORY_BRANCH'], ''))
|
||||
@@ -31,7 +61,10 @@ jobs:
|
||||
$ImageType = "${{ parameters.image_type }}"
|
||||
$TemplateDirectoryName = if ($ImageType.StartsWith("ubuntu")) { "linux" } else { "win" }
|
||||
$TemplateDirectoryPath = Join-Path "images" $TemplateDirectoryName | Resolve-Path
|
||||
$TemplatePath = Join-Path $TemplateDirectoryPath "$ImageType.json"
|
||||
$TemplatePath = Join-Path $TemplateDirectoryPath "$ImageType.pkr.hcl"
|
||||
if ( -not (Test-Path $TemplatePath) ) {
|
||||
$TemplatePath = Join-Path $TemplateDirectoryPath "$ImageType.json"
|
||||
}
|
||||
Write-Host "##vso[task.setvariable variable=TemplateDirectoryPath;]$TemplateDirectoryPath"
|
||||
Write-Host "##vso[task.setvariable variable=TemplatePath;]$TemplatePath"
|
||||
|
||||
@@ -55,35 +88,64 @@ jobs:
|
||||
|
||||
env:
|
||||
PACKER_LOG: 1
|
||||
PACKER_LOG_PATH: $(Build.ArtifactStagingDirectory)/packer-log.txt
|
||||
|
||||
PACKER_LOG_PATH: "$(Agent.TempDirectory)/packer-log.txt"
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Output Readme file content'
|
||||
displayName: 'Copy image artifacts to the separate directory'
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
Get-Content -Path (Join-Path "$(TemplateDirectoryPath)" "${{ parameters.image_readme_name }}")
|
||||
$readmePath = Join-Path "$(TemplateDirectoryPath)" "${{ parameters.image_readme_name }}"
|
||||
$softwareReportPath = Join-Path "$(TemplateDirectoryPath)" "software-report.json"
|
||||
|
||||
Copy-Item -Path $readmePath -Destination "$(Build.ArtifactStagingDirectory)/"
|
||||
if (Test-Path $softwareReportPath) {
|
||||
Copy-Item -Path $softwareReportPath -Destination "$(Build.ArtifactStagingDirectory)/"
|
||||
}
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Print markdown software report'
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
Get-Content -Path "$(Build.ArtifactStagingDirectory)/${{ parameters.image_readme_name }}"
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Print json software report'
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
$softwareReportPath = "$(Build.ArtifactStagingDirectory)/software-report.json"
|
||||
if (Test-Path $softwareReportPath) {
|
||||
Get-Content -Path $softwareReportPath
|
||||
}
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
ArtifactName: 'Built_VM_Artifacts'
|
||||
displayName: Publish Artifacts
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Print provisioners duration'
|
||||
inputs:
|
||||
targetType: 'filePath'
|
||||
filePath: ./images.CI/measure-provisioners-duration.ps1
|
||||
arguments: -PackerLogPath "$(Build.ArtifactStagingDirectory)/packer-log.txt" `
|
||||
arguments: -PackerLogPath "$(Agent.TempDirectory)/packer-log.txt" `
|
||||
-PrefixToPathTrim "$(TemplateDirectoryPath)" `
|
||||
-PrintTopNLongest 25
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Create release for VM deployment'
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: ./images.CI/linux-and-win/create-release.ps1
|
||||
arguments: -BuildId $(Build.BuildId) `
|
||||
-Organization $(RELEASE_TARGET_ORGANIZATION) `
|
||||
-DefinitionId $(RELEASE_TARGET_DEFINITION_ID) `
|
||||
-Project $(RELEASE_TARGET_PROJECT) `
|
||||
-ImageName ${{ parameters.image_type }} `
|
||||
-AccessToken $(RELEASE_TARGET_TOKEN)
|
||||
- ${{ if eq(parameters.create_release, true) }}:
|
||||
- task: PowerShell@2
|
||||
displayName: 'Create release for VM deployment'
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: ./images.CI/linux-and-win/create-release.ps1
|
||||
arguments: -BuildId $(Build.BuildId) `
|
||||
-Organization $(RELEASE_TARGET_ORGANIZATION) `
|
||||
-DefinitionId $(RELEASE_TARGET_DEFINITION_ID) `
|
||||
-Project $(RELEASE_TARGET_PROJECT) `
|
||||
-ImageName ${{ parameters.image_type }} `
|
||||
-AccessToken $(RELEASE_TARGET_TOKEN)
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Clean up resources'
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
- template: image-generation.yml
|
||||
parameters:
|
||||
image_type: ubuntu1804
|
||||
image_readme_name: Ubuntu1804-Readme.md
|
||||
@@ -1,11 +1,3 @@
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
- template: image-generation.yml
|
||||
parameters:
|
||||
image_type: ubuntu2204
|
||||
image_readme_name: Ubuntu2204-Readme.md
|
||||
@@ -1,20 +0,0 @@
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
- template: image-generation.yml
|
||||
parameters:
|
||||
image_type: windows2016
|
||||
image_readme_name: Windows2016-Readme.md
|
||||
@@ -1,11 +1,3 @@
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
@@ -8,9 +8,9 @@ param(
|
||||
[String] [Parameter (Mandatory=$true)] $StorageAccount,
|
||||
[String] [Parameter (Mandatory=$true)] $SubscriptionId,
|
||||
[String] [Parameter (Mandatory=$true)] $TenantId,
|
||||
[String] [Parameter (Mandatory=$true)] $VirtualNetworkName,
|
||||
[String] [Parameter (Mandatory=$true)] $VirtualNetworkRG,
|
||||
[String] [Parameter (Mandatory=$true)] $VirtualNetworkSubnet
|
||||
[String] [Parameter (Mandatory=$false)] $VirtualNetworkName,
|
||||
[String] [Parameter (Mandatory=$false)] $VirtualNetworkRG,
|
||||
[String] [Parameter (Mandatory=$false)] $VirtualNetworkSubnet
|
||||
)
|
||||
|
||||
if (-not (Test-Path $TemplatePath))
|
||||
@@ -19,7 +19,7 @@ if (-not (Test-Path $TemplatePath))
|
||||
exit 1
|
||||
}
|
||||
|
||||
$Image = [io.path]::GetFileNameWithoutExtension($TemplatePath)
|
||||
$Image = [io.path]::GetFileName($TemplatePath).Split(".")[0]
|
||||
$TempResourceGroupName = "${ResourcesNamePrefix}_${Image}"
|
||||
$InstallPassword = [System.GUID]::NewGuid().ToString().ToUpper()
|
||||
|
||||
@@ -53,10 +53,11 @@ packer build -var "capture_name_prefix=$ResourcesNamePrefix" `
|
||||
-var "virtual_network_resource_group_name=$VirtualNetworkRG" `
|
||||
-var "virtual_network_subnet_name=$VirtualNetworkSubnet" `
|
||||
-var "run_validation_diskspace=$env:RUN_VALIDATION_FLAG" `
|
||||
-color=false `
|
||||
$TemplatePath `
|
||||
| Where-Object {
|
||||
#Filter sensitive data from Packer logs
|
||||
$currentString = $_
|
||||
$sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ }
|
||||
$sensitiveString -eq $null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ $TempResourceGroupName = "${ResourcesNamePrefix}_${Image}"
|
||||
|
||||
$groupExist = az group exists --name $TempResourceGroupName --subscription $SubscriptionId
|
||||
if ($groupExist -eq "true") {
|
||||
$osDiskName = az group deployment list --resource-group $TempResourceGroupName --query "[].properties.parameters.osDiskName.value" -o tsv
|
||||
$osDiskName = az deployment group list --resource-group $TempResourceGroupName --query "[].properties.parameters.osDiskName.value" -o tsv
|
||||
Write-Host "Found a match, deleting temporary files"
|
||||
az group delete --name $TempResourceGroupName --subscription $SubscriptionId --yes | Out-Null
|
||||
Write-Host "Temporary group was deleted succesfully"
|
||||
Write-Host "Temporary group was deleted successfully"
|
||||
Write-Host "Deleting OS disk"
|
||||
az storage remove --account-name $StorageAccount -c "images" -n "$osDiskName.vhd" --only-show-errors | Out-Null
|
||||
Write-Host "OS disk deleted"
|
||||
|
||||
@@ -26,6 +26,7 @@ $headers = @{
|
||||
Authorization = "Basic ${base64AuthInfo}"
|
||||
}
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13
|
||||
$NewRelease = Invoke-RestMethod $URL -Body $Body -Method "POST" -Headers $headers -ContentType "application/json"
|
||||
|
||||
Write-Host "Created release: $($NewRelease._links.web.href)"
|
||||
@@ -14,15 +14,16 @@ function Push-AnkaTemplateToRegistry {
|
||||
)
|
||||
|
||||
# if registry uuid doesn't match than delete an image in registry
|
||||
$images = anka --machine-readable registry --registry-path $RegistryUrl list | ConvertFrom-Json | ForEach-Object body
|
||||
$AnkaCaCrtPath="$HOME/.config/anka/certs/anka-ca-crt.pem"
|
||||
$images = anka --machine-readable registry --cacert $AnkaCaCrtPath --registry-path $RegistryUrl list | ConvertFrom-Json | ForEach-Object body
|
||||
$images | Where-Object name -eq $TemplateName | ForEach-Object {
|
||||
$id = $_.id
|
||||
$id = $_.uuid
|
||||
Show-StringWithFormat "Deleting '$TemplateName[$id]' VM and '$TagName' tag"
|
||||
$uri = '{0}/registry/vm?id={1}' -f $RegistryUrl, $id
|
||||
Invoke-WebRequest -Uri $uri -Method Delete | Out-Null
|
||||
$curlCommand='curl -s -X DELETE -k "{0}/registry/vm?id={1}"' -f $RegistryUrl, $id
|
||||
Invoke-AnkaCommand -Command $curlCommand
|
||||
}
|
||||
|
||||
$command = "anka registry --registry-path $RegistryUrl push --force --tag $TagName $TemplateName"
|
||||
$command = "anka registry --cacert $AnkaCaCrtPath --registry-path $RegistryUrl push --force --tag $TagName $TemplateName"
|
||||
Invoke-AnkaCommand -Command $command
|
||||
}
|
||||
|
||||
@@ -197,7 +198,14 @@ function Wait-AnkaVMIPAddress {
|
||||
[int] $Seconds = 60
|
||||
)
|
||||
|
||||
$condition = { Get-AnkaVMIPAddress -VMName $VMName }
|
||||
$condition = {
|
||||
$vmStatus = Get-AnkaVMStatus -VMName $VMName
|
||||
if ($vmStatus -eq "failed") {
|
||||
Write-Host "`t [-] $VMName is in failed status"
|
||||
exit 1
|
||||
}
|
||||
Get-AnkaVMIPAddress -VMName $VMName
|
||||
}
|
||||
$null = Invoke-WithRetry -BreakCondition $condition -RetryCount $RetryCount -Seconds $Seconds
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,12 @@ function Invoke-EnableAutoLogon {
|
||||
}
|
||||
|
||||
function Invoke-SoftwareUpdate {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Password
|
||||
)
|
||||
|
||||
if (-not $InstallSoftwareUpdate) {
|
||||
Write-Host "`t[*] Skip installing software updates"
|
||||
return
|
||||
@@ -81,26 +87,32 @@ function Invoke-SoftwareUpdate {
|
||||
|
||||
Write-Host "`t[*] Fetching Software Updates ready to install on '$TemplateName' VM:"
|
||||
Show-StringWithFormat $newUpdates
|
||||
$listOfNewUpdates = $($($newUpdates.Split("*")).Split("Title") | Where-Object {$_ -match "Label:"}).Replace("Label: ", '')
|
||||
Write-Host "`t[*] Installing Software Updates on '$TemplateName' VM:"
|
||||
Install-SoftwareUpdate -HostName $ipAddress | Show-StringWithFormat
|
||||
Install-SoftwareUpdate -HostName $ipAddress -listOfUpdates $listOfNewUpdates -Password $Password | Show-StringWithFormat
|
||||
|
||||
# Check if Action: restart
|
||||
if ($newUpdates.Contains("Action: restart")) {
|
||||
Write-Host "`t[*] Sleep 60 seconds before the software updates have been installed"
|
||||
Start-Sleep -Seconds 60
|
||||
# Make an array of updates
|
||||
$listOfNewUpdates = $newUpdates.split('*').Trim('')
|
||||
foreach ($newupdate in $listOfNewUpdates) {
|
||||
# Will be True if the value is not Venture, not empty, and contains "Action: restart" words
|
||||
if ($newupdate.Contains("Action: restart") -and !$newupdate.Contains("macOS Ventura") -and (-not [String]::IsNullOrEmpty($newupdate))) {
|
||||
Write-Host "`t[*] Sleep 60 seconds before the software updates have been installed"
|
||||
Start-Sleep -Seconds 60
|
||||
|
||||
Write-Host "`t[*] Waiting for loginwindow process"
|
||||
Wait-LoginWindow -HostName $ipAddress | Show-StringWithFormat
|
||||
Write-Host "`t[*] Waiting for loginwindow process"
|
||||
Wait-LoginWindow -HostName $ipAddress | Show-StringWithFormat
|
||||
|
||||
# Re-enable AutoLogon after installing a new security software update
|
||||
Invoke-EnableAutoLogon
|
||||
# Re-enable AutoLogon after installing a new security software update
|
||||
Invoke-EnableAutoLogon
|
||||
|
||||
# Check software updates have been installed
|
||||
$updates = Get-SoftwareUpdate -HostName $ipAddress
|
||||
if ($updates.Contains("Action: restart")) {
|
||||
Write-Host "`t[x] Software updates failed to install: $updates"
|
||||
Show-StringWithFormat $updates
|
||||
exit 1
|
||||
# Check software updates have been installed
|
||||
$updates = Get-SoftwareUpdate -HostName $ipAddress
|
||||
if ($updates.Contains("Action: restart")) {
|
||||
Write-Host "`t[x] Software updates failed to install: "
|
||||
Show-StringWithFormat $updates
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +122,11 @@ function Invoke-SoftwareUpdate {
|
||||
}
|
||||
|
||||
function Invoke-UpdateSettings {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Password
|
||||
)
|
||||
$isConfRequired = $InstallSoftwareUpdate -or $EnableAutoLogon
|
||||
if (-not $isConfRequired) {
|
||||
Write-Host "`t[*] Skip additional configuration"
|
||||
@@ -126,7 +143,7 @@ function Invoke-UpdateSettings {
|
||||
Invoke-EnableAutoLogon
|
||||
|
||||
# Install software updates
|
||||
Invoke-SoftwareUpdate
|
||||
Invoke-SoftwareUpdate -Password $Password
|
||||
|
||||
Write-Host "`t[*] Stopping '$TemplateName' VM"
|
||||
Stop-AnkaVM -VMName $TemplateName
|
||||
@@ -145,10 +162,16 @@ $env:SSHUSER = $TemplateUsername
|
||||
$env:SSHPASS = $TemplatePassword
|
||||
|
||||
Write-Host "`n[#1] Download macOS application installer:"
|
||||
$macOSInstaller = Get-MacOSInstaller -MacOSVersion $MacOSVersion -DownloadLatestVersion $DownloadLatestVersion -BetaSearch $BetaSearch
|
||||
$shortMacOSVersion = Get-ShortMacOSVersion -MacOSVersion $MacOSVersion
|
||||
if ([string]::IsNullOrEmpty($TemplateName)) {
|
||||
$TemplateName = "clean_macos_${shortMacOSVersion}_${DiskSizeGb}gb"
|
||||
$osArch = $(arch)
|
||||
if ($osArch -eq "arm64") {
|
||||
$macOSInstaller = Get-MacOSIPSWInstaller -MacOSVersion $MacOSVersion -DownloadLatestVersion $DownloadLatestVersion -BetaSearch $BetaSearch
|
||||
$TemplateName = "clean_macos_${shortMacOSVersion}_${osArch}_${DiskSizeGb}gb"
|
||||
} else {
|
||||
$macOSInstaller = Get-MacOSInstaller -MacOSVersion $MacOSVersion -DownloadLatestVersion $DownloadLatestVersion -BetaSearch $BetaSearch
|
||||
$TemplateName = "clean_macos_${shortMacOSVersion}_${DiskSizeGb}gb"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n[#2] Create a VM template:"
|
||||
@@ -166,7 +189,7 @@ New-AnkaVMTemplate -InstallerPath $macOSInstaller `
|
||||
-DiskSizeGb $DiskSizeGb | Show-StringWithFormat
|
||||
|
||||
Write-Host "`n[#3] Configure AutoLogon and/or install software updates:"
|
||||
Invoke-UpdateSettings
|
||||
Invoke-UpdateSettings -Password $TemplatePassword
|
||||
|
||||
Write-Host "`n[#4] Finalization '$TemplateName' configuration and push to the registry:"
|
||||
Write-Host "`t[*] The '$TemplateName' VM status is stopped"
|
||||
|
||||
@@ -13,12 +13,28 @@ function Enable-AutoLogon {
|
||||
[string] $Password
|
||||
)
|
||||
|
||||
$url = "https://raw.githubusercontent.com/actions/virtual-environments/main/images/macos/provision/bootstrap-provisioner/kcpassword.py"
|
||||
$url = "https://raw.githubusercontent.com/actions/runner-images/main/images/macos/provision/bootstrap-provisioner/setAutoLogin.sh"
|
||||
$script = Invoke-RestMethod -Uri $url
|
||||
$base64 = [Convert]::ToBase64String($script.ToCharArray())
|
||||
$kcpassword = "echo $base64 | base64 --decode > ~/kcpassword;sudo python ./kcpassword '${Password}';rm ./kcpassword"
|
||||
$loginwindow = "sudo /usr/bin/defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser '${UserName}';sudo /usr/bin/defaults write /Library/Preferences/com.apple.loginwindow autoLoginUserScreenLocked -bool false"
|
||||
$command = "${kcpassword};$loginwindow"
|
||||
$command = "echo $base64 | base64 --decode > ./setAutoLogin.sh;sudo bash ./setAutoLogin.sh '${UserName}' '${Password}';rm ./setAutoLogin.sh"
|
||||
Invoke-SSHPassCommand -HostName $HostName -Command $command
|
||||
}
|
||||
|
||||
function Invoke-SoftwareUpdateArm64 {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $HostName,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Password
|
||||
)
|
||||
|
||||
$url = "https://raw.githubusercontent.com/actions/runner-images/main/images/macos/provision/configuration/auto-software-update-arm64.exp"
|
||||
$script = Invoke-RestMethod -Uri $url
|
||||
$base64 = [Convert]::ToBase64String($script.ToCharArray())
|
||||
$command = "echo $base64 | base64 --decode > ./auto-software-update-arm64.exp;chmod +x ./auto-software-update-arm64.exp; ./auto-software-update-arm64.exp ${Password};rm ./auto-software-update-arm64.exp"
|
||||
Invoke-SSHPassCommand -HostName $HostName -Command $command
|
||||
}
|
||||
|
||||
@@ -39,6 +55,84 @@ function Get-AvailableVersions {
|
||||
$allVersions
|
||||
}
|
||||
|
||||
function Get-AvailableIPSWVersions {
|
||||
param (
|
||||
[bool] $IsBeta = $false,
|
||||
[bool] $IsLatest = $true,
|
||||
[string] $MacOSCodeNameOrVersion
|
||||
)
|
||||
|
||||
if ($IsBeta) {
|
||||
$command = { mist list installer "$MacOSCodeNameOrVersion" --include-betas --latest --export "/Applications/export.json"}
|
||||
} elseif ($IsLatest) {
|
||||
$command = { mist list installer "$MacOSCodeNameOrVersion" --latest --export "/Applications/export.json" }
|
||||
} else {
|
||||
$command = { mist list installer "$MacOSCodeNameOrVersion" --export "/Applications/export.json" }
|
||||
}
|
||||
|
||||
$condition = { $LASTEXITCODE -eq 0 }
|
||||
Invoke-WithRetry -Command $command -BreakCondition $condition | Out-Null
|
||||
$softwareList = get-content -Path "/Applications/export.json"
|
||||
$turgetVersion = ($softwareList | ConvertFrom-Json).version
|
||||
if ($null -eq $turgetVersion) {
|
||||
Write-Host "Requested macOS '$MacOSCodeNameOrVersion' version not found in the list of available installers."
|
||||
$command = { mist list installer "$($MacOSCodeNameOrVersion.split('.')[0])" }
|
||||
Invoke-WithRetry -Command $command -BreakCondition $condition
|
||||
exit 1
|
||||
}
|
||||
return $turgetVersion
|
||||
}
|
||||
|
||||
function Get-MacOSIPSWInstaller {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[version] $MacOSVersion,
|
||||
|
||||
[bool] $DownloadLatestVersion = $false,
|
||||
[bool] $BetaSearch = $false
|
||||
)
|
||||
|
||||
if ($MacOSVersion -eq [version] "12.0") {
|
||||
$MacOSName = "macOS Monterey"
|
||||
} elseif ($MacOSVersion -eq [version] "13.0") {
|
||||
$MacOSName = "macOS Ventura"
|
||||
} else {
|
||||
$MacOSName = $MacOSVersion.ToString()
|
||||
}
|
||||
|
||||
|
||||
Write-Host "`t[*] Finding available full installers"
|
||||
if ($DownloadLatestVersion -eq $true) {
|
||||
$targetVersion = Get-AvailableIPSWVersions -IsLatest $true -MacOSCodeNameOrVersion $MacOSName
|
||||
Write-host "`t[*] The 'DownloadLatestVersion' flag is set to true. Latest macOS version is '$MacOSName' - '$targetVersion' now"
|
||||
} elseif ($BetaSearch -eq $true) {
|
||||
$targetVersion = Get-AvailableIPSWVersions -IsBeta $true -MacOSCodeNameOrVersion $MacOSName
|
||||
Write-host "`t[*] The 'BetaSearch' flag is set to true. Latestbeta macOS version is '$MacOSName' - '$targetVersion' now"
|
||||
} else {
|
||||
$targetVersion = Get-AvailableIPSWVersions -MacOSCodeNameOrVersion $MacOSName
|
||||
Write-host "`t[*] The exact version was specified - '$MacOSName' "
|
||||
}
|
||||
|
||||
$installerPathPattern = "/Applications/Install ${macOSName}*.ipsw"
|
||||
if (Test-Path $installerPathPattern) {
|
||||
$previousInstallerPath = Get-Item -Path $installerPathPattern
|
||||
Write-Host "`t[*] Removing '$previousInstallerPath' installation app before downloading the new one"
|
||||
sudo rm -rf "$previousInstallerPath"
|
||||
}
|
||||
|
||||
# Download macOS installer
|
||||
$installerDir = "/Applications/"
|
||||
$installerName = "Install ${macOSName}.ipsw"
|
||||
Write-Host "`t[*] Requested macOS '$targetVersion' version installer found, fetching it from mist database"
|
||||
Invoke-WithRetry { mist download firmware "$targetVersion" --output-directory $installerDir --firmware-name "$installerName" } {$LASTEXITCODE -eq 0} | Out-Null
|
||||
if (Test-Path "$installerDir$installerName") {
|
||||
$result = "$installerDir$installerName"
|
||||
} else {
|
||||
Write-host "`t[*] Requested macOS '$targetVersion' version installer failed to download"
|
||||
exit 1
|
||||
}
|
||||
return $result
|
||||
}
|
||||
function Get-MacOSInstaller {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
@@ -73,20 +167,20 @@ function Get-MacOSInstaller {
|
||||
Show-StringWithFormat $availableVersions
|
||||
exit 1
|
||||
}
|
||||
Show-StringWithFormat $filteredVersions
|
||||
Show-StringWithFormat $filteredVersions
|
||||
$osVersions = $filteredVersions.OSVersion | Sort-Object {[version]$_}
|
||||
$MacOSVersion = $osVersions | Select-Object -Last 1
|
||||
Write-Host "`t[*] The 'DownloadLatestVersion' flag is set. Latest macOS version is '$MacOSVersion' now"
|
||||
}
|
||||
|
||||
$macOSName = $availableVersions.Where{ $MacOSVersion -eq $_.OSVersion }.OSName
|
||||
$macOSName = $availableVersions.Where{ $MacOSVersion -eq $_.OSVersion }.OSName.Split(" ")[1]
|
||||
if (-not $macOSName) {
|
||||
Write-Host "`t[x] Requested macOS '$MacOSVersion' version not found in the list of available installers. Available versions are:`n$($availableVersions.OSVersion)"
|
||||
Write-Host "`t[x] Make sure to pass '-BetaSearch `$true' if you need a beta version installer"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$installerPathPattern = "/Applications/Install*${macOSName}.app"
|
||||
$installerPathPattern = "/Applications/Install macOS ${macOSName}*.app"
|
||||
if (Test-Path $installerPathPattern) {
|
||||
$previousInstallerPath = Get-Item -Path $installerPathPattern
|
||||
Write-Host "`t[*] Removing '$previousInstallerPath' installation app before downloading the new one"
|
||||
@@ -106,6 +200,10 @@ function Get-MacOSInstaller {
|
||||
}
|
||||
|
||||
$installerPath = (Get-Item -Path $installerPathPattern).FullName
|
||||
if (-not $installerPath) {
|
||||
Write-Host "`t[x] Path not found using '$installerPathPattern'"
|
||||
exit 1
|
||||
}
|
||||
Write-Host "`t[*] Installer successfully downloaded to '$installerPath'"
|
||||
|
||||
$installerPath
|
||||
@@ -148,11 +246,29 @@ function Install-SoftwareUpdate {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $HostName
|
||||
[string] $HostName,
|
||||
[array] $listOfUpdates,
|
||||
[string] $Password
|
||||
)
|
||||
|
||||
$command = "sudo /usr/sbin/softwareupdate --all --install --restart --verbose"
|
||||
Invoke-SSHPassCommand -HostName $HostName -Command $command
|
||||
$osVersion = [Environment]::OSVersion
|
||||
# If an update is happening on macOS 12 we will use the prepared list of updates, otherwise, we will install all updates.
|
||||
if ($osVersion.Version.Major -eq "12") {
|
||||
foreach ($update in $listOfUpdates){
|
||||
# Filtering updates that contain "Ventura" word
|
||||
if ($update -notmatch "Ventura") {
|
||||
$command = "sudo /usr/sbin/softwareupdate --restart --verbose --install '$($update.trim())'"
|
||||
Invoke-SSHPassCommand -HostName $HostName -Command $command
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$osArch = $(arch)
|
||||
if ($osArch -eq "arm64") {
|
||||
Invoke-SoftwareUpdateArm64 -HostName $HostName -Password $Password
|
||||
} else {
|
||||
$command = "sudo /usr/sbin/softwareupdate --all --install --restart --verbose"
|
||||
Invoke-SSHPassCommand -HostName $HostName -Command $command
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-SSHPassCommand {
|
||||
@@ -230,7 +346,7 @@ function Show-StringWithFormat {
|
||||
[Parameter(ValuefromPipeline)]
|
||||
[object] $string
|
||||
)
|
||||
|
||||
|
||||
process {
|
||||
($string | Out-String).Trim().split("`n") | ForEach-Object { Write-Host "`t $_" }
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ jobs:
|
||||
arguments: -VMName "$(VirtualMachineName)" `
|
||||
-VIServer "$(vcenter-server-v2)" `
|
||||
-VIUserName "$(vcenter-username-v2)" `
|
||||
-VIPassword "$(vcenter-password-v2)"
|
||||
-VIPassword '$(vcenter-password-v2)' `
|
||||
-Cluster "$(esxi-cluster-v2)"
|
||||
|
||||
- pwsh: |
|
||||
$SensitiveData = @(
|
||||
@@ -66,13 +67,14 @@ jobs:
|
||||
packer build -on-error=abort `
|
||||
-var="vcenter_server=$(vcenter-server-v2)" `
|
||||
-var="vcenter_username=$(vcenter-username-v2)" `
|
||||
-var="vcenter_password=$(vcenter-password-v2)" `
|
||||
-var='vcenter_password=$(vcenter-password-v2)' `
|
||||
-var="vcenter_datacenter=$(vcenter-datacenter-v2)" `
|
||||
-var="cluster_or_esxi_host=$(esxi-cluster-v2)" `
|
||||
-var="esxi_datastore=$(buildDatastore)" `
|
||||
-var="output_folder=$(output-folder)" `
|
||||
-var="vm_username=$(vm-username)" `
|
||||
-var="vm_password=$(vm-password)" `
|
||||
-var="github_api_pat=$(github_api_pat)" `
|
||||
-var="build_id=$(VirtualMachineName)" `
|
||||
-var="baseimage_name=${{ parameters.base_image_name }}" `
|
||||
-var="xcode_install_user=$(xcode-installation-user)" `
|
||||
@@ -105,7 +107,11 @@ jobs:
|
||||
|
||||
- bash: |
|
||||
cat "$(Build.ArtifactStagingDirectory)/systeminfo.md"
|
||||
displayName: Print software report
|
||||
displayName: Print markdown software report
|
||||
|
||||
- bash: |
|
||||
cat "$(Build.ArtifactStagingDirectory)/systeminfo.json"
|
||||
displayName: Print json software report
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
@@ -130,7 +136,7 @@ jobs:
|
||||
-TargetDataStore "${{ parameters.target_datastore }}" `
|
||||
-VIServer "$(vcenter-server-v2)" `
|
||||
-VIUserName "$(vcenter-username-v2)" `
|
||||
-VIPassword "$(vcenter-password-v2)"
|
||||
-VIPassword '$(vcenter-password-v2)' `
|
||||
-CpuCount "$(cpu-count)" `
|
||||
-CoresPerSocketCount "$(cores-per-socket-count)" `
|
||||
-Memory "$(memory)"
|
||||
@@ -144,4 +150,4 @@ jobs:
|
||||
arguments: -VMName "$(VirtualMachineName)" `
|
||||
-VIServer "$(vcenter-server-v2)" `
|
||||
-VIUserName "$(vcenter-username-v2)" `
|
||||
-VIPassword "$(vcenter-password-v2)"
|
||||
-VIPassword '$(vcenter-password-v2)'
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: macOS-10.15_$(date:yyyyMMdd)$(rev:.r)_unstable
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
trigger: none
|
||||
pr:
|
||||
autoCancel: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
- template: image-generation.yml
|
||||
parameters:
|
||||
image_label: 'macOS Catalina'
|
||||
base_image_name: 'clean-macOS-10.15-380Gb-runner'
|
||||
template_path: 'templates/macOS-10.15.json'
|
||||
target_datastore: 'ds-image'
|
||||
@@ -1,6 +1,6 @@
|
||||
name: macOS-11_$(date:yyyyMMdd)$(rev:.r)_unstable
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
- cron: '45 0 * * *'
|
||||
displayName: Daily
|
||||
branches:
|
||||
include:
|
||||
|
||||
@@ -41,6 +41,8 @@ param(
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VIPassword,
|
||||
|
||||
[string]$JobStatus,
|
||||
|
||||
[int32]$CpuCount,
|
||||
|
||||
[int32]$CoresPerSocketCount,
|
||||
@@ -62,15 +64,16 @@ try {
|
||||
}
|
||||
|
||||
$vm = Get-VM $VMName
|
||||
if ($env:AGENT_JOBSTATUS -eq 'Failed') {
|
||||
if (($env:AGENT_JOBSTATUS -and $env:AGENT_JOBSTATUS -eq 'Failed') -or ($JobStatus -and $JobStatus -eq 'failure')) {
|
||||
try {
|
||||
if($vm.PowerState -ne "PoweredOff") {
|
||||
if ($vm.PowerState -ne "PoweredOff") {
|
||||
Stop-VM -VM $vm -Confirm:$false -ErrorAction Stop | Out-Null
|
||||
}
|
||||
Set-VM -VM $vm -Name "${VMName}_failed" -Confirm:$false -ErrorAction Stop | Out-Null
|
||||
Write-Host "VM has been successfully powered off and renamed to [${VMName}_failed]"
|
||||
} catch {
|
||||
Write-Host "##vso[task.LogIssue type=error;]Failed to power off and rename VM '$VMName'"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +82,5 @@ try {
|
||||
Write-Host "VM has been moved successfully to target datastore '$TargetDataStore'"
|
||||
} catch {
|
||||
Write-Host "##vso[task.LogIssue type=error;]Failed to move VM '$VMName' to target datastore '$TargetDataStore'"
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Host "Change CPU count to $CpuCount, cores count to $CoresPerSocketCount, amount of RAM to $Memory"
|
||||
$vm | Set-VM -NumCPU $CpuCount -CoresPerSocket $CoresPerSocketCount -MemoryMB $Memory -Confirm:$false -ErrorAction Stop | Out-Null
|
||||
} catch {
|
||||
Write-Host "##vso[task.LogIssue type=error;]Failed to change specs for VM '$VMName'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ param(
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VIPassword,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Cluster,
|
||||
|
||||
[string]$TagCategory = "Busy"
|
||||
)
|
||||
|
||||
@@ -47,6 +51,7 @@ function Select-DataStore {
|
||||
[string]$VMName,
|
||||
[string]$TagCategory,
|
||||
[string]$TemplateDatastore = "ds-local-Datastore-*",
|
||||
[string]$Cluster,
|
||||
[int]$ThresholdInGb = 400,
|
||||
[int]$VMCount = 2,
|
||||
[int]$Retries = 5
|
||||
@@ -57,11 +62,12 @@ function Select-DataStore {
|
||||
# 3. Choose a datastore with the minimal VM count < 2
|
||||
|
||||
Write-Host "Start Datastore selection process..."
|
||||
$allDatastores = Get-Datastore -Name $templateDatastore | Where-Object { $_.State -eq "Available" }
|
||||
$availableDatastores = $allDatastores `
|
||||
$clusterHosts = Get-Cluster -Name $Cluster | Get-VMHost
|
||||
$availableClusterDatastores = $clusterHosts | Get-Datastore -Name $TemplateDatastore | Where-Object -Property State -eq "Available"
|
||||
$availableDatastores = $availableClusterDatastores `
|
||||
| Where-Object { $_.FreeSpaceGB -ge $thresholdInGb } `
|
||||
| Where-Object {
|
||||
$vmOnDatastore = @((Get-ChildItem -Path $_.DatastoreBrowserPath).Name -notmatch "^\.").Count
|
||||
$vmOnDatastore = @((Get-ChildItem -Path $_.DatastoreBrowserPath).Name -notmatch '(^\.|vmkdump)').Count
|
||||
$vmOnDatastore -lt $vmCount } `
|
||||
| Group-Object -Property { $vmOnDatastore }
|
||||
|
||||
@@ -101,11 +107,11 @@ function Select-DataStore {
|
||||
}
|
||||
|
||||
Write-Host "Datastore select failed, $retries left"
|
||||
Select-DataStore -VMName $VMName -TagCategory $TagCategory -Retries $retries
|
||||
Select-DataStore -VMName $VMName -Cluster $Cluster -TagCategory $TagCategory -Retries $retries
|
||||
}
|
||||
|
||||
# Connection to a vCenter Server system
|
||||
Connect-VCServer -VIServer $VIServer -VIUserName $VIUserName -VIPassword $VIPassword
|
||||
|
||||
# Get a target datastore for current deployment
|
||||
Select-DataStore -VMName $VMName -TagCategory $TagCategory
|
||||
Select-DataStore -VMName $VMName -Cluster $Cluster -TagCategory $TagCategory
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
This script sets resources for VM
|
||||
|
||||
.PARAMETER VMName
|
||||
VM name to resize (Example "macOS-10.15_20201012.4")
|
||||
|
||||
.PARAMETER VIServer
|
||||
vCenter address (Example "10.0.1.16")
|
||||
|
||||
.PARAMETER VIUserName
|
||||
vCenter username (Example "Administrator")
|
||||
|
||||
.PARAMETER VIPassword
|
||||
vCenter password (Example "12345678")
|
||||
|
||||
.PARAMETER CpuCount
|
||||
Target number of CPUs (Example "3")
|
||||
|
||||
.PARAMETER CoresPerSocketCount
|
||||
Target number of cores per socket (Example "3")
|
||||
|
||||
.PARAMETER Memory
|
||||
Target amount of memory in MB (Example "14336")
|
||||
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VMName,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VIServer,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VIUserName,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$VIPassword,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int32]$CpuCount,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int32]$CoresPerSocketCount,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int64]$Memory
|
||||
)
|
||||
|
||||
# Import helpers module
|
||||
Import-Module $PSScriptRoot\helpers.psm1 -DisableNameChecking
|
||||
|
||||
# Connection to a vCenter Server system
|
||||
Connect-VCServer -VIServer $VIServer -VIUserName $VIUserName -VIPassword $VIPassword
|
||||
|
||||
$vm = Get-VM $VMName
|
||||
try {
|
||||
Write-Host "Change CPU count to $CpuCount, cores count to $CoresPerSocketCount, amount of RAM to $Memory"
|
||||
$vm | Set-VM -NumCPU $CpuCount -CoresPerSocket $CoresPerSocketCount -MemoryMB $Memory -Confirm:$false -ErrorAction Stop | Out-Null
|
||||
} catch {
|
||||
Write-Host "##vso[task.LogIssue type=error;]Failed to change specs for VM '$VMName'"
|
||||
exit 1
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
| Announcements |
|
||||
|-|
|
||||
| [[All OSs] Az PowerShell Module will be upgraded to 7.1.0 on January, 17](https://github.com/actions/virtual-environments/issues/4841) |
|
||||
| [[Ubuntu] Issue with libstdc++ cannot allocate memory in static TLS block](https://github.com/actions/virtual-environments/issues/4799) |
|
||||
| [[All OSs] Python version 3.5 will be removed from the images on January 24, 2022](https://github.com/actions/virtual-environments/issues/4744) |
|
||||
***
|
||||
# Ubuntu 18.04.6 LTS
|
||||
- Linux kernel version: 5.4.0-1065-azure
|
||||
- Image Version: 20220111.1
|
||||
|
||||
## Installed Software
|
||||
### Language and Runtime
|
||||
- Bash 4.4.20(1)-release
|
||||
- Clang 9.0.0
|
||||
- Clang-format 9.0.0
|
||||
- Erlang 24.1.7 (Eshell 12.1.5)
|
||||
- Erlang rebar3 3.18.0
|
||||
- GNU C++ 7.5.0, 9.4.0, 10.3.0
|
||||
- GNU Fortran 7.5.0, 9.4.0, 10.3.0
|
||||
- Julia 1.7.1
|
||||
- Kotlin 1.6.0-release-798
|
||||
- Mono 6.12.0.122 (apt source repository: https://download.mono-project.com/repo/ubuntu stable-bionic main)
|
||||
- MSBuild 16.6.0.15201 (from /usr/lib/mono/msbuild/15.0/bin/MSBuild.dll)
|
||||
- Node 16.13.2
|
||||
- Perl 5.26.1
|
||||
- Python 2.7.17
|
||||
- Python3 3.6.9
|
||||
- Ruby 2.5.1p57
|
||||
- Swift 5.5.2
|
||||
|
||||
### Package Management
|
||||
- cpan 1.64
|
||||
- Helm 3.7.2
|
||||
- Homebrew 3.3.10
|
||||
- Miniconda 4.10.3
|
||||
- Npm 8.1.2
|
||||
- Pip 9.0.1
|
||||
- Pip3 9.0.1
|
||||
- Pipx 1.0.0
|
||||
- RubyGems 2.7.6
|
||||
- Vcpkg (build from master \<b8b1217bd>)
|
||||
- Yarn 1.22.17
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------------- | ---------------------- |
|
||||
| CONDA | /usr/share/miniconda |
|
||||
| VCPKG_INSTALLATION_ROOT | /usr/local/share/vcpkg |
|
||||
|
||||
### Project Management
|
||||
- Ant 1.10.5
|
||||
- Gradle 7.3.3
|
||||
- Maven 3.8.4
|
||||
- Sbt 1.6.1
|
||||
|
||||
### Tools
|
||||
- Ansible 2.11.7
|
||||
- apt-fast 1.9.11
|
||||
- AzCopy 10.13.0 (available by `azcopy` and `azcopy10` aliases)
|
||||
- Bazel 4.2.2
|
||||
- Bazelisk 1.11.0
|
||||
- Bicep 0.4.1124
|
||||
- Buildah 1.19.6 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- CMake 3.22.1
|
||||
- CodeQL Action Bundle 2.7.3
|
||||
- Docker Compose v1 1.29.2
|
||||
- Docker Compose v2 2.2.2+azure-1
|
||||
- Docker-Buildx 0.7.1
|
||||
- Docker-Moby Client 20.10.11+azure-3
|
||||
- Docker-Moby Server 20.10.11+azure-3
|
||||
- Git 2.34.1 (apt source repository: ppa:git-core/ppa)
|
||||
- Git LFS 3.0.2 (apt source repository: https://packagecloud.io/install/repositories/github/git-lfs)
|
||||
- Git-ftp 1.3.1
|
||||
- Haveged 1.9.1
|
||||
- Heroku 7.59.2
|
||||
- HHVM (HipHop VM) 4.143.0
|
||||
- jq 1.5
|
||||
- Kind 0.11.1
|
||||
- Kubectl 1.23.1
|
||||
- Kustomize 4.4.1
|
||||
- Leiningen 2.9.8
|
||||
- MediaInfo 17.12
|
||||
- Mercurial 4.5.3
|
||||
- Minikube 1.24.0
|
||||
- n 8.0.2
|
||||
- Newman 5.3.1
|
||||
- nvm 0.39.1
|
||||
- OpenSSL 1.1.1 11 Sep 2018
|
||||
- Packer 1.7.8
|
||||
- Parcel 2.1.1
|
||||
- PhantomJS 2.1.1
|
||||
- Podman 3.0.1 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- Pulumi 3.21.1
|
||||
- R 4.1.2
|
||||
- Skopeo 1.2.2 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- Sphinx Open Source Search Server 2.2.11
|
||||
- SVN 1.9.7
|
||||
- Terraform 1.1.3
|
||||
- yamllint 1.26.3
|
||||
- yq 4.16.2
|
||||
- zstd 1.5.1 (homebrew)
|
||||
|
||||
### CLI Tools
|
||||
- Alibaba Cloud CLI 3.0.102
|
||||
- AWS CLI 1.22.33
|
||||
- AWS CLI Session manager plugin 1.2.295.0
|
||||
- AWS SAM CLI 1.37.0
|
||||
- Azure CLI (azure-cli) 2.32.0 (installation method: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)
|
||||
- Azure CLI (azure-devops) 0.22.0
|
||||
- GitHub CLI 2.4.0
|
||||
- Google Cloud SDK 368.0.0 (apt source repository: https://packages.cloud.google.com/apt)
|
||||
- Hub CLI 2.14.2
|
||||
- Netlify CLI 8.6.21
|
||||
- OpenShift CLI 4.9.13
|
||||
- ORAS CLI 0.12.0
|
||||
- Vercel CLI 23.1.2
|
||||
|
||||
### Java
|
||||
| Version | Vendor | Environment Variable |
|
||||
| ------------------- | ------------- | -------------------- |
|
||||
| 8.0.292+1 (default) | Adopt OpenJDK | JAVA_HOME_8_X64 |
|
||||
| 11.0.11+9 | Adopt OpenJDK | JAVA_HOME_11_X64 |
|
||||
| 12.0.2+10 | Adopt OpenJDK | JAVA_HOME_12_X64 |
|
||||
|
||||
### PHP
|
||||
| Tool | Version |
|
||||
| -------- | ---------------------------------------- |
|
||||
| PHP | 7.1.33 7.2.34 7.3.33 7.4.27 8.0.14 8.1.1 |
|
||||
| Composer | 2.2.4 |
|
||||
| PHPUnit | 8.5.22 |
|
||||
```
|
||||
Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled.
|
||||
```
|
||||
### Haskell
|
||||
- Cabal 3.6.2.0
|
||||
- GHC 9.2.1
|
||||
- GHCup 0.1.17.4
|
||||
- Stack 2.7.3
|
||||
|
||||
### Rust Tools
|
||||
- Cargo 1.57.0
|
||||
- Rust 1.57.0
|
||||
- Rustdoc 1.57.0
|
||||
- Rustup 1.24.3
|
||||
|
||||
#### Packages
|
||||
- Bindgen 0.59.2
|
||||
- Cargo audit 0.16.0
|
||||
- Cargo clippy 0.1.57
|
||||
- Cargo outdated 0.10.2
|
||||
- Cbindgen 0.20.0
|
||||
- Rustfmt 1.4.37
|
||||
|
||||
### Browsers and Drivers
|
||||
- Google Chrome 97.0.4692.71
|
||||
- ChromeDriver 97.0.4692.71
|
||||
- Mozilla Firefox 95.0.1
|
||||
- Geckodriver 0.30.0
|
||||
- Chromium 97.0.4692.0
|
||||
- Selenium server 4.1.0
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------- | ----------------------------------- |
|
||||
| CHROMEWEBDRIVER | /usr/local/share/chrome_driver |
|
||||
| GECKOWEBDRIVER | /usr/local/share/gecko_driver |
|
||||
| SELENIUM_JAR_PATH | /usr/share/java/selenium-server.jar |
|
||||
|
||||
### .NET Core SDK
|
||||
- 2.1.302 2.1.403 2.1.526 2.1.617 2.1.701 2.1.818 3.1.120 3.1.202 3.1.302 3.1.416 5.0.104 5.0.210 5.0.303 5.0.404
|
||||
|
||||
### Databases
|
||||
- MongoDB 5.0.5 (apt source repository: https://repo.mongodb.org/apt/ubuntu)
|
||||
- PostgreSQL 14.1 (apt source repository: https://apt.postgresql.org/pub/repos/apt/)
|
||||
- sqlite3 3.22.0
|
||||
|
||||
#### MySQL
|
||||
- MySQL 5.7.36
|
||||
- MySQL Server (user:root password:root)
|
||||
|
||||
```
|
||||
MySQL service is disabled by default. Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'
|
||||
```
|
||||
#### MS SQL Server Client Tools
|
||||
- sqlcmd 17.8.0001.1
|
||||
- SqlPackage 15.0.5282.3
|
||||
|
||||
### Cached Tools
|
||||
#### Go
|
||||
- 1.15.15
|
||||
- 1.16.13
|
||||
- 1.17.6
|
||||
|
||||
#### Node.js
|
||||
- 12.22.9
|
||||
- 14.18.3
|
||||
- 16.13.2
|
||||
|
||||
#### PyPy
|
||||
- 2.7.18 [PyPy 7.3.6]
|
||||
- 3.6.12 [PyPy 7.3.3]
|
||||
|
||||
#### Python
|
||||
- 2.7.18
|
||||
- 3.5.10
|
||||
- 3.6.15
|
||||
- 3.7.12
|
||||
- 3.8.12
|
||||
- 3.9.9
|
||||
- 3.10.1
|
||||
|
||||
#### Ruby
|
||||
- 2.4.10
|
||||
- 2.5.9
|
||||
- 2.6.9
|
||||
- 2.7.5
|
||||
- 3.0.3
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value | Architecture |
|
||||
| --------------- | ----------------------------------- | ------------ |
|
||||
| GOROOT_1_15_X64 | /opt/hostedtoolcache/go/1.15.15/x64 | x64 |
|
||||
| GOROOT_1_16_X64 | /opt/hostedtoolcache/go/1.16.13/x64 | x64 |
|
||||
| GOROOT_1_17_X64 | /opt/hostedtoolcache/go/1.17.6/x64 | x64 |
|
||||
|
||||
### PowerShell Tools
|
||||
- PowerShell 7.2.1
|
||||
|
||||
#### PowerShell Modules
|
||||
| Module | Version |
|
||||
| ---------- | ------- |
|
||||
| MarkdownPS | 1.9 |
|
||||
| Pester | 5.3.1 |
|
||||
|
||||
#### Az PowerShell Modules
|
||||
- 6.4.0 3.1.0.zip 4.4.0.zip 5.9.0.zip
|
||||
|
||||
### Web Servers
|
||||
| Name | Version | ConfigFile | ServiceStatus | ListenPort |
|
||||
| ------- | ------- | ------------------------- | ------------- | ---------- |
|
||||
| apache2 | 2.4.29 | /etc/apache2/apache2.conf | inactive | 80 |
|
||||
| nginx | 1.14.0 | /etc/nginx/nginx.conf | inactive | 80 |
|
||||
|
||||
### Android
|
||||
| Package Name | Version |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Android Command Line Tools | 4.0 |
|
||||
| Android Emulator | 31.1.4 |
|
||||
| Android SDK Build-tools | 32.0.0<br>31.0.0<br>30.0.0 30.0.1 30.0.2 30.0.3<br>29.0.0 29.0.1 29.0.2 29.0.3<br>28.0.0 28.0.1 28.0.2 28.0.3<br>27.0.0 27.0.1 27.0.2 27.0.3<br>26.0.0 26.0.1 26.0.2 26.0.3<br>25.0.0 25.0.1 25.0.2 25.0.3<br>24.0.0 24.0.1 24.0.2 24.0.3<br>23.0.1 23.0.2 23.0.3 |
|
||||
| Android SDK Platform-Tools | 31.0.3 |
|
||||
| Android SDK Platforms | android-32 (rev 1)<br>android-31 (rev 1)<br>android-30 (rev 3)<br>android-29 (rev 5)<br>android-28 (rev 6)<br>android-27 (rev 3)<br>android-26 (rev 2)<br>android-25 (rev 3)<br>android-24 (rev 2)<br>android-23 (rev 3) |
|
||||
| Android SDK Tools | 26.1.1 |
|
||||
| Android Support Repository | 47.0.0 |
|
||||
| CMake | 3.10.2<br>3.18.1 |
|
||||
| Google APIs | addon-google_apis-google-21<br>addon-google_apis-google-22<br>addon-google_apis-google-23<br>addon-google_apis-google-24 |
|
||||
| Google Play services | 49 |
|
||||
| Google Repository | 58 |
|
||||
| NDK | 21.4.7075529 (default)<br>23.1.7779620 |
|
||||
| SDK Patch Applier v4 | 1 |
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------ |
|
||||
| ANDROID_HOME | /usr/local/lib/android/sdk |
|
||||
| ANDROID_NDK_HOME | /usr/local/lib/android/sdk/ndk-bundle -> /usr/local/lib/android/sdk/ndk/21.4.7075529 |
|
||||
| ANDROID_NDK_LATEST_HOME | /usr/local/lib/android/sdk/ndk/23.1.7779620 |
|
||||
| ANDROID_NDK_ROOT | /usr/local/lib/android/sdk/ndk-bundle -> /usr/local/lib/android/sdk/ndk/21.4.7075529 |
|
||||
| ANDROID_SDK_ROOT | /usr/local/lib/android/sdk |
|
||||
|
||||
### Cached Docker images
|
||||
| Repository:Tag | Digest | Created |
|
||||
| ----------------------- | ------------------------------------------------------------------------ | ---------- |
|
||||
| alpine:3.12 | sha256:d9459083f962de6bd980ae6a05be2a4cf670df6a1d898157bceb420342bec280 | 2021-11-12 |
|
||||
| alpine:3.13 | sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c | 2021-11-12 |
|
||||
| alpine:3.14 | sha256:635f0aa53d99017b38d1a0aa5b2082f7812b03e3cdb299103fe77b5c8a07f1d2 | 2021-11-12 |
|
||||
| buildpack-deps:bullseye | sha256:8cca6f729d85d572000a436eac498ff5358eeee5a0fa7b3e2b6668620c6ac06e | 2021-12-21 |
|
||||
| buildpack-deps:buster | sha256:24cf4668129a284b9b960ffaa5e79f9654d7d040708721c8e7708811e362a9d9 | 2021-12-21 |
|
||||
| buildpack-deps:stretch | sha256:19610095f7d1718c20d79e5109c42f64dabea9fdf104221394acdf2999170c51 | 2021-12-21 |
|
||||
| debian:10 | sha256:94ccfd1c5115a6903cbb415f043a0b04e307be3f37b768cf6d6d3edff0021da3 | 2021-12-21 |
|
||||
| debian:11 | sha256:2906804d2a64e8a13a434a1a127fe3f6a28bf7cf3696be4223b06276f32f1f2d | 2021-12-21 |
|
||||
| debian:9 | sha256:54284a7a45383b407c1968657e8f1c50dc25b82d8d56b3812e46ad19f8bcfd83 | 2021-12-21 |
|
||||
| moby/buildkit:latest | sha256:d6c89b7085b106301645ddcc77cf64eb7b705ab507b72d52d130ac33f1300417 | 2021-11-18 |
|
||||
| node:12 | sha256:36b3ee4724ab60ac5f288d22999074437ed517e8d1bd2e24ab19609479d39c81 | 2021-12-21 |
|
||||
| node:12-alpine | sha256:05d61228b85c54b5527e74afc54153eb3572aae005948fb068a0f4ebe01f7c1e | 2022-01-03 |
|
||||
| node:14 | sha256:e5c6aac226819f88d6431a56f502972d323d052b1b6108094ba7e6b07154a542 | 2021-12-21 |
|
||||
| node:14-alpine | sha256:1e7481a9a977d8e4160a73ed6a0e726724570bf7d941adbec63a82cf7c07ae19 | 2022-01-03 |
|
||||
| node:16 | sha256:32605ead97ed57bd39a8a7b0e919240e1a3218974dfc6965e61b54a801753131 | 2021-12-21 |
|
||||
| node:16-alpine | sha256:0e071f3c5c84cffa6b1035023e1956cf28d48f4b36e229cef328772da81ec0c5 | 2022-01-03 |
|
||||
| ubuntu:16.04 | sha256:0f71fa8d4d2d4292c3c617fda2b36f6dabe5c8b6e34c3dc5b0d17d4e704bd39c | 2021-08-31 |
|
||||
| ubuntu:18.04 | sha256:37b7471c1945a2a12e5a57488ee4e3e216a8369d0b9ee1ec2e41db9c2c1e3d22 | 2022-01-07 |
|
||||
| ubuntu:20.04 | sha256:b5a61709a9a44284d88fb12e5c48db0409cfad5b69d4ff8224077c57302df9cf | 2022-01-07 |
|
||||
|
||||
### Installed apt packages
|
||||
| Name | Version |
|
||||
| ----------------- | --------------------------------- |
|
||||
| aria2 | 1.33.1-1 |
|
||||
| binutils | 2.30-21ubuntu1\~18.04.7 |
|
||||
| bison | 2:3.0.4.dfsg-1build1 |
|
||||
| brotli | 1.0.3-1ubuntu1.3 |
|
||||
| build-essential | 12.4ubuntu1 |
|
||||
| bzip2 | 1.0.6-8.1ubuntu0.2 |
|
||||
| coreutils | 8.28-1ubuntu1 |
|
||||
| curl | 7.58.0-2ubuntu3.16 |
|
||||
| dbus | 1.12.2-1ubuntu1.2 |
|
||||
| dnsutils | 1:9.11.3+dfsg-1ubuntu1.16 |
|
||||
| dpkg | 1.19.0.5ubuntu2.3 |
|
||||
| fakeroot | 1.22-2ubuntu1 |
|
||||
| file | 1:5.32-2ubuntu0.4 |
|
||||
| flex | 2.6.4-6 |
|
||||
| ftp | 0.17-34 |
|
||||
| gnupg2 | 2.2.4-1ubuntu1.4 |
|
||||
| haveged | 1.9.1-6 |
|
||||
| imagemagick | 8:6.9.7.4+dfsg-16ubuntu6.12 |
|
||||
| iproute2 | 4.15.0-2ubuntu1.3 |
|
||||
| iputils-ping | 3:20161105-1ubuntu3 |
|
||||
| jq | 1.5+dfsg-2 |
|
||||
| lib32z1 | 1:1.2.11.dfsg-0ubuntu2 |
|
||||
| libc++-dev | 6.0-2 |
|
||||
| libc++abi-dev | 6.0-2 |
|
||||
| libcurl3 | 7.58.0-2ubuntu3.16 |
|
||||
| libgbm-dev | 20.0.8-0ubuntu1\~18.04.1 |
|
||||
| libgconf-2-4 | 3.2.6-4ubuntu1 |
|
||||
| libgsl-dev | 2.4+dfsg-6 |
|
||||
| libgtk-3-0 | 3.22.30-1ubuntu4 |
|
||||
| libmagic-dev | 1:5.32-2ubuntu0.4 |
|
||||
| libmagickcore-dev | 8:6.9.7.4+dfsg-16ubuntu6.12 |
|
||||
| libmagickwand-dev | 8:6.9.7.4+dfsg-16ubuntu6.12 |
|
||||
| libsecret-1-dev | 0.18.6-1 |
|
||||
| libsqlite3-dev | 3.22.0-1ubuntu0.4 |
|
||||
| libunwind8 | 1.2.1-8 |
|
||||
| libxkbfile-dev | 1:1.0.9-2 |
|
||||
| libxss1 | 1:1.2.2-1 |
|
||||
| locales | 2.27-3ubuntu1.4 |
|
||||
| m4 | 1.4.18-1 |
|
||||
| mediainfo | 17.12-1 |
|
||||
| mercurial | 4.5.3-1ubuntu2.2 |
|
||||
| net-tools | 1.60+git20161116.90da8a0-1ubuntu1 |
|
||||
| netcat | 1.10-41.1 |
|
||||
| openssh-client | 1:7.6p1-4ubuntu0.5 |
|
||||
| p7zip-full | 16.02+dfsg-6 |
|
||||
| p7zip-rar | 16.02-2 |
|
||||
| parallel | 20161222-1 |
|
||||
| pass | 1.7.1-3 |
|
||||
| patchelf | 0.9-1 |
|
||||
| pkg-config | 0.29.1-0ubuntu2 |
|
||||
| pollinate | 4.33-0ubuntu1\~18.04.2 |
|
||||
| python-setuptools | 39.0.1-2 |
|
||||
| rpm | 4.14.1+dfsg1-2 |
|
||||
| rsync | 3.1.2-2.1ubuntu1.2 |
|
||||
| shellcheck | 0.4.6-1 |
|
||||
| sphinxsearch | 2.2.11-2 |
|
||||
| sqlite3 | 3.22.0-1ubuntu0.4 |
|
||||
| ssh | 1:7.6p1-4ubuntu0.5 |
|
||||
| sshpass | 1.06-1 |
|
||||
| subversion | 1.9.7-4ubuntu1 |
|
||||
| sudo | 1.8.21p2-3ubuntu1.4 |
|
||||
| swig | 3.0.12-1 |
|
||||
| telnet | 0.17-41 |
|
||||
| texinfo | 6.5.0.dfsg.1-2 |
|
||||
| time | 1.7-25.1build1 |
|
||||
| tk | 8.6.0+9 |
|
||||
| tzdata | 2021e-0ubuntu0.18.04 |
|
||||
| unzip | 6.0-21ubuntu1.1 |
|
||||
| upx | 3.94-4 |
|
||||
| wget | 1.19.4-1ubuntu2.2 |
|
||||
| xorriso | 1.4.8-3 |
|
||||
| xvfb | 2:1.19.6-1ubuntu4.10 |
|
||||
| xz-utils | 5.2.2-1.3 |
|
||||
| zip | 3.0-11build1 |
|
||||
| zsync | 0.6.2-3ubuntu1 |
|
||||
|
||||
|
||||
+252
-231
@@ -1,45 +1,49 @@
|
||||
| Announcements |
|
||||
|-|
|
||||
| [[All OSs] Az PowerShell Module will be upgraded to 7.1.0 on January, 17](https://github.com/actions/virtual-environments/issues/4841) |
|
||||
| [[Ubuntu] Issue with libstdc++ cannot allocate memory in static TLS block](https://github.com/actions/virtual-environments/issues/4799) |
|
||||
| [[All OSs] Python version 3.5 will be removed from the images on January 24, 2022](https://github.com/actions/virtual-environments/issues/4744) |
|
||||
| [python2.7 will be removed from the images on May 15, 2023](https://github.com/actions/runner-images/issues/7401) |
|
||||
***
|
||||
# Ubuntu 20.04.3 LTS
|
||||
- Linux kernel version: 5.11.0-1025-azure
|
||||
- Image Version: 20220111.1
|
||||
# Ubuntu 20.04
|
||||
- OS Version: 20.04.6 LTS
|
||||
- Kernel Version: 5.15.0-1037-azure
|
||||
- Image Version: 20230507.1
|
||||
- Systemd version: 245.4-4ubuntu3.21
|
||||
|
||||
## Installed Software
|
||||
|
||||
### Language and Runtime
|
||||
- Bash 5.0.17(1)-release
|
||||
- Clang 10.0.0, 11.0.0, 12.0.0
|
||||
- Clang-format 10.0.0, 11.0.0, 12.0.0
|
||||
- Erlang 24.1.7 (Eshell 12.1.5)
|
||||
- Erlang rebar3 3.18.0
|
||||
- GNU C++ 9.3.0, 10.3.0
|
||||
- GNU Fortran 9.3.0, 10.3.0
|
||||
- Julia 1.7.1
|
||||
- Kotlin 1.6.0-release-798
|
||||
- Mono 6.12.0.122 (apt source repository: https://download.mono-project.com/repo/ubuntu stable-focal main)
|
||||
- MSBuild 16.6.0.15201 (from /usr/lib/mono/msbuild/15.0/bin/MSBuild.dll)
|
||||
- Node 16.13.2
|
||||
- Clang: 10.0.0, 11.0.0, 12.0.0
|
||||
- Clang-format: 10.0.0, 11.0.0, 12.0.0
|
||||
- Clang-tidy: 10.0.0, 11.0.0, 12.0.0
|
||||
- Dash 0.5.10.2-6
|
||||
- Erlang 25.3 (Eshell 13.2)
|
||||
- Erlang rebar3 3.20.0
|
||||
- GNU C++: 9.4.0, 10.3.0
|
||||
- GNU Fortran: 9.4.0, 10.3.0
|
||||
- Julia 1.8.5
|
||||
- Kotlin 1.8.21-release-380
|
||||
- Mono 6.12.0.182
|
||||
- MSBuild 16.10.1.31701 (Mono 6.12.0.182)
|
||||
- Node.js 18.16.0
|
||||
- Perl 5.30.0
|
||||
- Python 3.8.10
|
||||
- Python3 3.8.10
|
||||
- Ruby 2.7.0p0
|
||||
- Swift 5.5.2
|
||||
- Swift 5.8
|
||||
|
||||
### Package Management
|
||||
- cpan 1.64
|
||||
- Helm 3.7.2
|
||||
- Homebrew 3.3.10
|
||||
- Miniconda 4.10.3
|
||||
- Npm 8.1.2
|
||||
- Helm 3.11.3
|
||||
- Homebrew 4.0.16
|
||||
- Miniconda 23.3.1
|
||||
- Npm 9.5.1
|
||||
- NuGet 6.3.1.1
|
||||
- Pip 20.0.2
|
||||
- Pip3 20.0.2
|
||||
- Pipx 1.0.0
|
||||
- Pipx 1.2.0
|
||||
- RubyGems 3.1.2
|
||||
- Vcpkg (build from master \<b8b1217bd>)
|
||||
- Yarn 1.22.17
|
||||
- Vcpkg (build from commit 6a3dd0874)
|
||||
- Yarn 1.22.19
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
@@ -47,201 +51,212 @@
|
||||
| CONDA | /usr/share/miniconda |
|
||||
| VCPKG_INSTALLATION_ROOT | /usr/local/share/vcpkg |
|
||||
|
||||
#### Homebrew note
|
||||
```
|
||||
Location: /home/linuxbrew
|
||||
Note: Homebrew is pre-installed on image but not added to PATH.
|
||||
run the eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" command
|
||||
to accomplish this.
|
||||
```
|
||||
|
||||
### Project Management
|
||||
- Ant 1.10.7
|
||||
- Gradle 7.3.3
|
||||
- Lerna 4.0.0
|
||||
- Maven 3.8.4
|
||||
- Sbt 1.6.1
|
||||
- Gradle 8.1.1
|
||||
- Lerna 6.6.2
|
||||
- Maven 3.8.8
|
||||
- Sbt 1.8.2
|
||||
|
||||
### Tools
|
||||
- Ansible 2.12.1
|
||||
- apt-fast 1.9.11
|
||||
- AzCopy 10.13.0 (available by `azcopy` and `azcopy10` aliases)
|
||||
- Bazel 4.2.2
|
||||
- Bazelisk 1.11.0
|
||||
- Bicep 0.4.1124
|
||||
- Buildah 1.21.3 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- CMake 3.22.1
|
||||
- CodeQL Action Bundle 2.7.3
|
||||
- Ansible 2.13.9
|
||||
- apt-fast 1.9.12
|
||||
- AzCopy 10.18.1 - available by `azcopy` and `azcopy10` aliases
|
||||
- Bazel 6.1.2
|
||||
- Bazelisk 1.13.2
|
||||
- Bicep 0.17.1
|
||||
- Buildah 1.22.3
|
||||
- CMake 3.26.3
|
||||
- CodeQL Action Bundles 2.13.0 2.13.1
|
||||
- Docker Amazon ECR Credential Helper 0.7.0
|
||||
- Docker Compose v1 1.29.2
|
||||
- Docker Compose v2 2.2.2+azure-1
|
||||
- Docker-Buildx 0.7.1
|
||||
- Docker-Moby Client 20.10.11+azure-3
|
||||
- Docker-Moby Server 20.10.11+azure-3
|
||||
- Fastlane 2.199.0
|
||||
- Git 2.34.1 (apt source repository: ppa:git-core/ppa)
|
||||
- Git LFS 3.0.2 (apt source repository: https://packagecloud.io/install/repositories/github/git-lfs)
|
||||
- Docker Compose v2 2.17.3+azure-1
|
||||
- Docker-Buildx 0.10.4
|
||||
- Docker-Moby Client 20.10.24+azure-1
|
||||
- Docker-Moby Server 20.10.24+azure-1
|
||||
- Fastlane 2.212.2
|
||||
- Git 2.40.1
|
||||
- Git LFS 3.3.0
|
||||
- Git-ftp 1.6.0
|
||||
- Haveged 1.9.1
|
||||
- Heroku 7.59.2
|
||||
- HHVM (HipHop VM) 4.143.0
|
||||
- Heroku 8.1.3
|
||||
- HHVM (HipHop VM) 4.172.1
|
||||
- jq 1.6
|
||||
- Kind 0.11.1
|
||||
- Kubectl 1.23.1
|
||||
- Kustomize 4.4.1
|
||||
- Leiningen 2.9.8
|
||||
- Kind 0.18.0
|
||||
- Kubectl 1.27.1
|
||||
- Kustomize 5.0.2
|
||||
- Leiningen 2.10.0
|
||||
- MediaInfo 19.09
|
||||
- Mercurial 5.3.1
|
||||
- Minikube 1.24.0
|
||||
- n 8.0.2
|
||||
- Newman 5.3.1
|
||||
- nvm 0.39.1
|
||||
- OpenSSL 1.1.1f 31 Mar 2020
|
||||
- Packer 1.7.8
|
||||
- Parcel 2.1.1
|
||||
- PhantomJS 2.1.1
|
||||
- Podman 3.4.2 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- Pulumi 3.21.1
|
||||
- R 4.1.2
|
||||
- Skopeo 1.3.0 (apt source repository: https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable)
|
||||
- Minikube 1.30.1
|
||||
- n 9.1.0
|
||||
- Newman 5.3.2
|
||||
- nvm 0.39.3
|
||||
- OpenSSL 1.1.1f-1ubuntu2.18
|
||||
- Packer 1.8.7
|
||||
- Parcel 2.8.3
|
||||
- PhantomJS 2.1.1 2.1.1
|
||||
- Podman 3.4.2
|
||||
- Pulumi 3.66.0
|
||||
- R 4.3.0
|
||||
- Skopeo 1.5.0
|
||||
- Sphinx Open Source Search Server 2.2.11
|
||||
- SVN 1.13.0
|
||||
- Terraform 1.1.3
|
||||
- yamllint 1.26.3
|
||||
- yq 4.16.2
|
||||
- zstd 1.5.1 (homebrew)
|
||||
- Terraform 1.4.6
|
||||
- yamllint 1.31.0
|
||||
- yq 4.33.3
|
||||
- zstd 1.5.5
|
||||
|
||||
### CLI Tools
|
||||
- Alibaba Cloud CLI 3.0.102
|
||||
- AWS CLI 2.4.9
|
||||
- AWS CLI Session manager plugin 1.2.295.0
|
||||
- AWS SAM CLI 1.37.0
|
||||
- Azure CLI (azure-cli) 2.32.0 (installation method: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)
|
||||
- Azure CLI (azure-devops) 0.22.0
|
||||
- GitHub CLI 2.4.0
|
||||
- Google Cloud SDK 368.0.0 (apt source repository: https://packages.cloud.google.com/apt)
|
||||
- Alibaba Cloud CLI 3.0.163
|
||||
- AWS CLI 2.11.18
|
||||
- AWS CLI Session Manager Plugin 1.2.463.0
|
||||
- AWS SAM CLI 1.82.0
|
||||
- Azure CLI 2.48.1
|
||||
- Azure CLI (azure-devops) 0.26.0
|
||||
- GitHub CLI 2.28.0
|
||||
- Google Cloud SDK 429.0.0
|
||||
- Hub CLI 2.14.2
|
||||
- Netlify CLI 8.6.21
|
||||
- OpenShift CLI 4.9.13
|
||||
- ORAS CLI 0.12.0
|
||||
- Vercel CLI 23.1.2
|
||||
- Netlify CLI 15.0.0
|
||||
- OpenShift CLI 4.12.15
|
||||
- ORAS CLI 1.0.0
|
||||
- Vercel CLI 29.1.1
|
||||
|
||||
### Java
|
||||
| Version | Vendor | Environment Variable |
|
||||
| ------------------- | ------------- | -------------------- |
|
||||
| 8.0.292+1 | Adopt OpenJDK | JAVA_HOME_8_X64 |
|
||||
| 11.0.11+9 (default) | Adopt OpenJDK | JAVA_HOME_11_X64 |
|
||||
| Version | Vendor | Environment Variable |
|
||||
| ------------------- | --------------- | -------------------- |
|
||||
| 8.0.362+9 | Eclipse Temurin | JAVA_HOME_8_X64 |
|
||||
| 11.0.19+7 (default) | Eclipse Temurin | JAVA_HOME_11_X64 |
|
||||
| 17.0.7+7 | Eclipse Temurin | JAVA_HOME_17_X64 |
|
||||
|
||||
### GraalVM
|
||||
| Version | Environment variables |
|
||||
| --------- | --------------------- |
|
||||
| CE 21.3.0 | GRAALVM_11_ROOT |
|
||||
### PHP Tools
|
||||
- PHP: 7.4.33, 8.0.28, 8.1.18, 8.2.5
|
||||
- Composer 2.5.5
|
||||
- PHPUnit 8.5.33
|
||||
```
|
||||
Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled.
|
||||
```
|
||||
|
||||
### PHP
|
||||
| Tool | Version |
|
||||
| -------- | ------------------- |
|
||||
| PHP | 7.4.27 8.0.14 8.1.1 |
|
||||
| Composer | 2.2.4 |
|
||||
| PHPUnit | 8.5.22 |
|
||||
```
|
||||
Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled.
|
||||
```
|
||||
### Haskell
|
||||
- Cabal 3.6.2.0
|
||||
- GHC 9.2.1
|
||||
- GHCup 0.1.17.4
|
||||
- Stack 2.7.3
|
||||
### Haskell Tools
|
||||
- Cabal 3.10.1.0
|
||||
- GHC 9.6.1
|
||||
- GHCup 0.1.19.2
|
||||
- Stack 2.9.3
|
||||
|
||||
### Rust Tools
|
||||
- Cargo 1.57.0
|
||||
- Rust 1.57.0
|
||||
- Rustdoc 1.57.0
|
||||
- Rustup 1.24.3
|
||||
- Cargo 1.69.0
|
||||
- Rust 1.69.0
|
||||
- Rustdoc 1.69.0
|
||||
- Rustup 1.26.0
|
||||
|
||||
#### Packages
|
||||
- Bindgen 0.59.2
|
||||
- Cargo audit 0.16.0
|
||||
- Cargo clippy 0.1.57
|
||||
- Cargo outdated 0.10.2
|
||||
- Cbindgen 0.20.0
|
||||
- Rustfmt 1.4.37
|
||||
- Bindgen 0.65.1
|
||||
- Cargo audit 0.17.5
|
||||
- Cargo clippy 0.1.69
|
||||
- Cargo outdated 0.11.2
|
||||
- Cbindgen 0.24.3
|
||||
- Rustfmt 1.5.2
|
||||
|
||||
### Browsers and Drivers
|
||||
- Google Chrome 97.0.4692.71
|
||||
- ChromeDriver 97.0.4692.71
|
||||
- Mozilla Firefox 95.0.1
|
||||
- Geckodriver 0.30.0
|
||||
- Chromium 97.0.4692.0
|
||||
- Selenium server 4.1.0
|
||||
- Google Chrome 113.0.5672.63
|
||||
- ChromeDriver 113.0.5672.63
|
||||
- Chromium 113.0.5672.0
|
||||
- Microsoft Edge 113.0.1774.35
|
||||
- Microsoft Edge WebDriver 113.0.1774.35
|
||||
- Selenium server 4.9.0
|
||||
- Mozilla Firefox 113.0
|
||||
- Geckodriver 0.33.0
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------- | ----------------------------------- |
|
||||
| CHROMEWEBDRIVER | /usr/local/share/chrome_driver |
|
||||
| EDGEWEBDRIVER | /usr/local/share/edge_driver |
|
||||
| GECKOWEBDRIVER | /usr/local/share/gecko_driver |
|
||||
| SELENIUM_JAR_PATH | /usr/share/java/selenium-server.jar |
|
||||
|
||||
### .NET Core SDK
|
||||
- 2.1.302 2.1.403 2.1.526 2.1.617 2.1.701 2.1.818 3.1.120 3.1.202 3.1.302 3.1.416 5.0.104 5.0.210 5.0.303 5.0.404
|
||||
### .NET Tools
|
||||
- .NET Core SDK: 3.1.120, 3.1.202, 3.1.302, 3.1.426, 6.0.408, 7.0.105, 7.0.203
|
||||
- nbgv 3.6.128+518ee610d6
|
||||
|
||||
### Databases
|
||||
- MongoDB 5.0.5 (apt source repository: https://repo.mongodb.org/apt/ubuntu)
|
||||
- PostgreSQL 14.1 (apt source repository: https://apt.postgresql.org/pub/repos/apt/)
|
||||
- MongoDB 5.0.17
|
||||
- sqlite3 3.31.1
|
||||
|
||||
#### MySQL
|
||||
- MySQL 8.0.26
|
||||
- MySQL Server (user:root password:root)
|
||||
#### PostgreSQL
|
||||
- PostgreSQL 14.7
|
||||
```
|
||||
User: postgres
|
||||
PostgreSQL service is disabled by default.
|
||||
Use the following command as a part of your job to start the service: 'sudo systemctl start postgresql.service'
|
||||
```
|
||||
|
||||
#### MySQL
|
||||
- MySQL 8.0.32-0ubuntu0.20.04.2
|
||||
```
|
||||
MySQL service is disabled by default. Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'
|
||||
User: root
|
||||
Password: root
|
||||
MySQL service is disabled by default.
|
||||
Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'
|
||||
```
|
||||
#### MS SQL Server Client Tools
|
||||
- sqlcmd 17.8.0001.1
|
||||
- SqlPackage 15.0.5282.3
|
||||
|
||||
#### MS SQL
|
||||
- sqlcmd 17.10.0001.1
|
||||
- SqlPackage 16.1.8089.0
|
||||
|
||||
### Cached Tools
|
||||
|
||||
#### Go
|
||||
- 1.15.15
|
||||
- 1.16.13
|
||||
- 1.17.6
|
||||
- 1.18.10
|
||||
- 1.19.9
|
||||
- 1.20.4
|
||||
|
||||
#### Node.js
|
||||
- 12.22.9
|
||||
- 14.18.3
|
||||
- 16.13.2
|
||||
|
||||
#### PyPy
|
||||
- 2.7.18 [PyPy 7.3.6]
|
||||
- 3.6.12 [PyPy 7.3.3]
|
||||
- 3.7.12 [PyPy 7.3.7]
|
||||
- 3.8.12 [PyPy 7.3.7]
|
||||
- 14.21.3
|
||||
- 16.20.0
|
||||
- 18.16.0
|
||||
|
||||
#### Python
|
||||
- 2.7.18
|
||||
- 3.5.10
|
||||
- 3.6.15
|
||||
- 3.7.12
|
||||
- 3.8.12
|
||||
- 3.9.9
|
||||
- 3.10.1
|
||||
- 3.7.16
|
||||
- 3.8.16
|
||||
- 3.9.16
|
||||
- 3.10.11
|
||||
- 3.11.3
|
||||
|
||||
#### PyPy
|
||||
- 2.7.18 [PyPy 7.3.11]
|
||||
- 3.6.12 [PyPy 7.3.3]
|
||||
- 3.7.13 [PyPy 7.3.9]
|
||||
- 3.8.16 [PyPy 7.3.11]
|
||||
- 3.9.16 [PyPy 7.3.11]
|
||||
|
||||
#### Ruby
|
||||
- 2.5.9
|
||||
- 2.6.9
|
||||
- 2.7.5
|
||||
- 3.0.3
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value | Architecture |
|
||||
| --------------- | ----------------------------------- | ------------ |
|
||||
| GOROOT_1_15_X64 | /opt/hostedtoolcache/go/1.15.15/x64 | x64 |
|
||||
| GOROOT_1_16_X64 | /opt/hostedtoolcache/go/1.16.13/x64 | x64 |
|
||||
| GOROOT_1_17_X64 | /opt/hostedtoolcache/go/1.17.6/x64 | x64 |
|
||||
- 2.6.10
|
||||
- 2.7.8
|
||||
- 3.0.6
|
||||
- 3.1.4
|
||||
|
||||
### PowerShell Tools
|
||||
- PowerShell 7.2.1
|
||||
- PowerShell 7.2.11
|
||||
|
||||
#### PowerShell Modules
|
||||
| Module | Version |
|
||||
| ---------------- | ------- |
|
||||
| MarkdownPS | 1.9 |
|
||||
| Pester | 5.3.1 |
|
||||
| PSScriptAnalyzer | 1.20.0 |
|
||||
|
||||
#### Az PowerShell Modules
|
||||
- 6.4.0 3.1.0.zip 4.4.0.zip 5.9.0.zip
|
||||
- Az: 9.3.0
|
||||
- Az (Cached): 3.1.0.zip, 4.4.0.zip, 5.9.0.zip, 6.6.0.zip, 7.5.0.zip
|
||||
- MarkdownPS: 1.9
|
||||
- Microsoft.Graph: 1.27.0
|
||||
- Pester: 5.4.1
|
||||
- PSScriptAnalyzer: 1.21.0
|
||||
|
||||
### Web Servers
|
||||
| Name | Version | ConfigFile | ServiceStatus | ListenPort |
|
||||
@@ -251,102 +266,108 @@
|
||||
| nginx | 1.18.0 | /etc/nginx/nginx.conf | inactive | 80 |
|
||||
|
||||
### Android
|
||||
| Package Name | Version |
|
||||
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Android Command Line Tools | 4.0 |
|
||||
| Android Emulator | 31.1.4 |
|
||||
| Android SDK Build-tools | 32.0.0<br>31.0.0<br>30.0.0 30.0.1 30.0.2 30.0.3<br>29.0.0 29.0.1 29.0.2 29.0.3<br>28.0.0 28.0.1 28.0.2 28.0.3<br>27.0.0 27.0.1 27.0.2 27.0.3 |
|
||||
| Android SDK Platform-Tools | 31.0.3 |
|
||||
| Android SDK Platforms | android-32 (rev 1)<br>android-31 (rev 1)<br>android-30 (rev 3)<br>android-29 (rev 5)<br>android-28 (rev 6)<br>android-27 (rev 3) |
|
||||
| Android SDK Tools | 26.1.1 |
|
||||
| Android Support Repository | 47.0.0 |
|
||||
| CMake | 3.10.2<br>3.18.1 |
|
||||
| Google Play services | 49 |
|
||||
| Google Repository | 58 |
|
||||
| NDK | 21.4.7075529 (default)<br>22.1.7171670<br>23.1.7779620 |
|
||||
| SDK Patch Applier v4 | 1 |
|
||||
| Package Name | Version |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Android Command Line Tools | 9.0 |
|
||||
| Android Emulator | 32.1.12 |
|
||||
| Android SDK Build-tools | 33.0.0 33.0.1 33.0.2<br>32.0.0<br>31.0.0<br>30.0.0 30.0.1 30.0.2 30.0.3<br>29.0.0 29.0.1 29.0.2 29.0.3<br>28.0.0 28.0.1 28.0.2 28.0.3<br>27.0.0 27.0.1 27.0.2 27.0.3 |
|
||||
| Android SDK Platform-Tools | 34.0.1 |
|
||||
| Android SDK Platforms | android-33-ext5 (rev 1)<br>android-33-ext4 (rev 1)<br>android-33 (rev 2)<br>android-32 (rev 1)<br>android-31 (rev 1)<br>android-30 (rev 3)<br>android-29 (rev 5)<br>android-28 (rev 6)<br>android-27 (rev 3) |
|
||||
| Android SDK Tools | 26.1.1 |
|
||||
| Android Support Repository | 47.0.0 |
|
||||
| CMake | 3.10.2<br>3.18.1<br>3.22.1 |
|
||||
| Google Play services | 49 |
|
||||
| Google Repository | 58 |
|
||||
| NDK | 23.2.8568313<br>24.0.8215888<br>25.2.9519653 (default) |
|
||||
| SDK Patch Applier v4 | 1 |
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------ |
|
||||
| ANDROID_HOME | /usr/local/lib/android/sdk |
|
||||
| ANDROID_NDK_HOME | /usr/local/lib/android/sdk/ndk-bundle -> /usr/local/lib/android/sdk/ndk/21.4.7075529 |
|
||||
| ANDROID_NDK_LATEST_HOME | /usr/local/lib/android/sdk/ndk/23.1.7779620 |
|
||||
| ANDROID_NDK_ROOT | /usr/local/lib/android/sdk/ndk-bundle -> /usr/local/lib/android/sdk/ndk/21.4.7075529 |
|
||||
| ANDROID_SDK_ROOT | /usr/local/lib/android/sdk |
|
||||
| Name | Value |
|
||||
| ----------------------- | ------------------------------------------- |
|
||||
| ANDROID_HOME | /usr/local/lib/android/sdk |
|
||||
| ANDROID_NDK | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_HOME | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_LATEST_HOME | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_ROOT | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_SDK_ROOT | /usr/local/lib/android/sdk |
|
||||
|
||||
### Cached Docker images
|
||||
| Repository:Tag | Digest | Created |
|
||||
| ----------------------- | ------------------------------------------------------------------------ | ---------- |
|
||||
| alpine:3.12 | sha256:d9459083f962de6bd980ae6a05be2a4cf670df6a1d898157bceb420342bec280 | 2021-11-12 |
|
||||
| alpine:3.13 | sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c | 2021-11-12 |
|
||||
| alpine:3.14 | sha256:635f0aa53d99017b38d1a0aa5b2082f7812b03e3cdb299103fe77b5c8a07f1d2 | 2021-11-12 |
|
||||
| buildpack-deps:bullseye | sha256:8cca6f729d85d572000a436eac498ff5358eeee5a0fa7b3e2b6668620c6ac06e | 2021-12-21 |
|
||||
| buildpack-deps:buster | sha256:24cf4668129a284b9b960ffaa5e79f9654d7d040708721c8e7708811e362a9d9 | 2021-12-21 |
|
||||
| buildpack-deps:stretch | sha256:19610095f7d1718c20d79e5109c42f64dabea9fdf104221394acdf2999170c51 | 2021-12-21 |
|
||||
| debian:10 | sha256:94ccfd1c5115a6903cbb415f043a0b04e307be3f37b768cf6d6d3edff0021da3 | 2021-12-21 |
|
||||
| debian:11 | sha256:2906804d2a64e8a13a434a1a127fe3f6a28bf7cf3696be4223b06276f32f1f2d | 2021-12-21 |
|
||||
| debian:9 | sha256:54284a7a45383b407c1968657e8f1c50dc25b82d8d56b3812e46ad19f8bcfd83 | 2021-12-21 |
|
||||
| moby/buildkit:latest | sha256:d6c89b7085b106301645ddcc77cf64eb7b705ab507b72d52d130ac33f1300417 | 2021-11-18 |
|
||||
| node:12 | sha256:36b3ee4724ab60ac5f288d22999074437ed517e8d1bd2e24ab19609479d39c81 | 2021-12-21 |
|
||||
| node:12-alpine | sha256:05d61228b85c54b5527e74afc54153eb3572aae005948fb068a0f4ebe01f7c1e | 2022-01-03 |
|
||||
| node:14 | sha256:e5c6aac226819f88d6431a56f502972d323d052b1b6108094ba7e6b07154a542 | 2021-12-21 |
|
||||
| node:14-alpine | sha256:1e7481a9a977d8e4160a73ed6a0e726724570bf7d941adbec63a82cf7c07ae19 | 2022-01-03 |
|
||||
| node:16 | sha256:32605ead97ed57bd39a8a7b0e919240e1a3218974dfc6965e61b54a801753131 | 2021-12-21 |
|
||||
| node:16-alpine | sha256:0e071f3c5c84cffa6b1035023e1956cf28d48f4b36e229cef328772da81ec0c5 | 2022-01-03 |
|
||||
| ubuntu:16.04 | sha256:0f71fa8d4d2d4292c3c617fda2b36f6dabe5c8b6e34c3dc5b0d17d4e704bd39c | 2021-08-31 |
|
||||
| ubuntu:18.04 | sha256:37b7471c1945a2a12e5a57488ee4e3e216a8369d0b9ee1ec2e41db9c2c1e3d22 | 2022-01-07 |
|
||||
| ubuntu:20.04 | sha256:b5a61709a9a44284d88fb12e5c48db0409cfad5b69d4ff8224077c57302df9cf | 2022-01-07 |
|
||||
| alpine:3.14 | sha256:0f2d5c38dd7a4f4f733e688e3a6733cb5ab1ac6e3cb4603a5dd564e5bfb80eed | 2023-03-29 |
|
||||
| alpine:3.15 | sha256:ecbdce53b2c2f43ab1b19418bcbd3f120a23547d9497030c8d978114512b883e | 2023-03-29 |
|
||||
| alpine:3.16 | sha256:c2b622f6e510a0d25bccaffa9e67b75a6860cb09b74bb58cfc36a9ef4331109f | 2023-03-29 |
|
||||
| alpine:3.17 | sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126 | 2023-03-29 |
|
||||
| buildpack-deps:bullseye | sha256:373587e78550f0918d16b793d1ead24c3f489a14c3af85da1096e2a683908e0c | 2023-05-03 |
|
||||
| buildpack-deps:buster | sha256:bfefe2afb02a82c76d955f2c158b3b5aa96e7afcf262727e8f37ccdea60a39c5 | 2023-05-03 |
|
||||
| buildpack-deps:stretch | sha256:78e995165a5788c2f55aed6e548d8f6c1534830d4310c870408fccb2da8c5b2e | 2022-06-23 |
|
||||
| debian:10 | sha256:cca6bcced970f7634197ff1821aabb452024eb437958ab98bfc146ece96969c6 | 2023-05-02 |
|
||||
| debian:11 | sha256:63d62ae233b588d6b426b7b072d79d1306bfd02a72bff1fc045b8511cc89ee09 | 2023-05-02 |
|
||||
| debian:9 | sha256:c5c5200ff1e9c73ffbf188b4a67eb1c91531b644856b4aefe86a58d2f0cb05be | 2022-06-23 |
|
||||
| moby/buildkit:latest | sha256:d6fa89830c26919acba23c5cafa09df0c3ec1fbde20bb2a15ff349e0795241f4 | 2023-04-20 |
|
||||
| node:14 | sha256:a158d3b9b4e3fa813fa6c8c590b8f0a860e015ad4e59bbce5744d2f6fd8461aa | 2023-04-12 |
|
||||
| node:14-alpine | sha256:434215b487a329c9e867202ff89e704d3a75e554822e07f3e0c0f9e606121b33 | 2023-03-29 |
|
||||
| node:16 | sha256:550f484fc5f314b575f5e397c9e2c71d7f218e59729fcda9ffa7ea1fc825dce7 | 2023-05-04 |
|
||||
| node:16-alpine | sha256:f1657204d3463bce763cefa5b25e48c28af6fe0cdb0f68b354f0f8225ef61be7 | 2023-03-29 |
|
||||
| node:18 | sha256:3f567a26b6b6d601fb2b168d4f987b50697617ead15bfc0e0152e600ac48d0fe | 2023-05-04 |
|
||||
| node:18-alpine | sha256:1ccc70acda680aa4ba47f53e7c40b2d4d6892de74817128e0662d32647dd7f4d | 2023-04-13 |
|
||||
| ubuntu:16.04 | sha256:1f1a2d56de1d604801a9671f301190704c25d604a416f59e03c04f5c6ffee0d6 | 2021-08-31 |
|
||||
| ubuntu:18.04 | sha256:8aa9c2798215f99544d1ce7439ea9c3a6dfd82de607da1cec3a8a2fae005931b | 2023-03-08 |
|
||||
| ubuntu:20.04 | sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3 | 2023-04-13 |
|
||||
|
||||
### Installed apt packages
|
||||
| Name | Version |
|
||||
| ---------------------- | --------------------------------- |
|
||||
| acl | 2.2.53-6 |
|
||||
| aria2 | 1.35.0-1build1 |
|
||||
| binutils | 2.34-6ubuntu1.3 |
|
||||
| autoconf | 2.69-11.1 |
|
||||
| automake | 1:1.16.1-4ubuntu6 |
|
||||
| binutils | 2.34-6ubuntu1.4 |
|
||||
| bison | 2:3.5.1+dfsg-1 |
|
||||
| brotli | 1.0.7-6ubuntu0.1 |
|
||||
| build-essential | 12.8ubuntu1.1 |
|
||||
| bzip2 | 1.0.8-2 |
|
||||
| coreutils | 8.30-3ubuntu2 |
|
||||
| curl | 7.68.0-1ubuntu2.7 |
|
||||
| dbus | 1.12.16-2ubuntu2.1 |
|
||||
| dnsutils | 1:9.16.1-0ubuntu2.9 |
|
||||
| dpkg | 1.19.7ubuntu3 |
|
||||
| curl | 7.68.0-1ubuntu2.18 |
|
||||
| dbus | 1.12.16-2ubuntu2.3 |
|
||||
| dnsutils | 1:9.16.1-0ubuntu2.14 |
|
||||
| dpkg | 1.19.7ubuntu3.2 |
|
||||
| fakeroot | 1.24-1 |
|
||||
| file | 1:5.38-4 |
|
||||
| flex | 2.6.4-6.2 |
|
||||
| fonts-noto-color-emoji | 0\~20200916-1\~ubuntu20.04.1 |
|
||||
| ftp | 0.17-34.1 |
|
||||
| gnupg2 | 2.2.19-3ubuntu2.1 |
|
||||
| gnupg2 | 2.2.19-3ubuntu2.2 |
|
||||
| haveged | 1.9.1-6ubuntu1 |
|
||||
| imagemagick | 8:6.9.10.23+dfsg-2.1ubuntu11.4 |
|
||||
| imagemagick | 8:6.9.10.23+dfsg-2.1ubuntu11.7 |
|
||||
| iproute2 | 5.5.0-1ubuntu1 |
|
||||
| iputils-ping | 3:20190709-3 |
|
||||
| jq | 1.6-1ubuntu0.20.04.1 |
|
||||
| lib32z1 | 1:1.2.11.dfsg-2ubuntu1.2 |
|
||||
| lib32z1 | 1:1.2.11.dfsg-2ubuntu1.5 |
|
||||
| libc++-dev | 1:10.0-50\~exp1 |
|
||||
| libc++abi-dev | 1:10.0-50\~exp1 |
|
||||
| libcurl4 | 7.68.0-1ubuntu2.7 |
|
||||
| libgbm-dev | 21.0.3-0ubuntu0.3\~20.04.5 |
|
||||
| libcurl4 | 7.68.0-1ubuntu2.18 |
|
||||
| libgbm-dev | 21.2.6-0ubuntu0.1\~20.04.2 |
|
||||
| libgconf-2-4 | 3.2.6-6ubuntu1 |
|
||||
| libgsl-dev | 2.5+dfsg-6build1 |
|
||||
| libgtk-3-0 | 3.24.20-0ubuntu1 |
|
||||
| libgtk-3-0 | 3.24.20-0ubuntu1.1 |
|
||||
| libmagic-dev | 1:5.38-4 |
|
||||
| libmagickcore-dev | 8:6.9.10.23+dfsg-2.1ubuntu11.4 |
|
||||
| libmagickwand-dev | 8:6.9.10.23+dfsg-2.1ubuntu11.4 |
|
||||
| libmagickcore-dev | 8:6.9.10.23+dfsg-2.1ubuntu11.7 |
|
||||
| libmagickwand-dev | 8:6.9.10.23+dfsg-2.1ubuntu11.7 |
|
||||
| libsecret-1-dev | 0.20.4-0ubuntu1 |
|
||||
| libsqlite3-dev | 3.31.1-4ubuntu0.2 |
|
||||
| libunwind8 | 1.2.1-9build1 |
|
||||
| libsqlite3-dev | 3.31.1-4ubuntu0.5 |
|
||||
| libtool | 2.4.6-14 |
|
||||
| libunwind8 | 1.2.1-9ubuntu0.1 |
|
||||
| libxkbfile-dev | 1:1.1.0-1 |
|
||||
| libxss1 | 1:1.2.3-1 |
|
||||
| locales | 2.31-0ubuntu9.2 |
|
||||
| libyaml-dev | 0.2.2-1 |
|
||||
| locales | 2.31-0ubuntu9.9 |
|
||||
| m4 | 1.4.18-4 |
|
||||
| mediainfo | 19.09-1build1 |
|
||||
| mercurial | 5.3.1-1ubuntu1 |
|
||||
| net-tools | 1.60+git20180626.aebd88e-1ubuntu1 |
|
||||
| netcat | 1.206-1ubuntu1 |
|
||||
| openssh-client | 1:8.2p1-4ubuntu0.4 |
|
||||
| openssh-client | 1:8.2p1-4ubuntu0.5 |
|
||||
| p7zip-full | 16.02+dfsg-7build1 |
|
||||
| p7zip-rar | 16.02-3build1 |
|
||||
| parallel | 20161222-1.1 |
|
||||
@@ -356,27 +377,27 @@
|
||||
| pollinate | 4.33-3ubuntu1.20.04.1 |
|
||||
| python-is-python3 | 3.8.2-4 |
|
||||
| rpm | 4.14.2.1+dfsg1-1build2 |
|
||||
| rsync | 3.1.3-8ubuntu0.1 |
|
||||
| rsync | 3.1.3-8ubuntu0.5 |
|
||||
| shellcheck | 0.7.0-2build2 |
|
||||
| sphinxsearch | 2.2.11-2ubuntu2 |
|
||||
| sqlite3 | 3.31.1-4ubuntu0.2 |
|
||||
| ssh | 1:8.2p1-4ubuntu0.4 |
|
||||
| sqlite3 | 3.31.1-4ubuntu0.5 |
|
||||
| ssh | 1:8.2p1-4ubuntu0.5 |
|
||||
| sshpass | 1.06-1 |
|
||||
| subversion | 1.13.0-3 |
|
||||
| sudo | 1.8.31-1ubuntu1.2 |
|
||||
| subversion | 1.13.0-3ubuntu0.2 |
|
||||
| sudo | 1.8.31-1ubuntu1.5 |
|
||||
| swig | 4.0.1-5build1 |
|
||||
| tar | 1.30+dfsg-7ubuntu0.20.04.3 |
|
||||
| telnet | 0.17-41.2build1 |
|
||||
| texinfo | 6.7.0.dfsg.2-5 |
|
||||
| time | 1.7-25.1build1 |
|
||||
| tk | 8.6.9+1 |
|
||||
| tzdata | 2021e-0ubuntu0.20.04 |
|
||||
| unzip | 6.0-25ubuntu1 |
|
||||
| tzdata | 2023c-0ubuntu0.20.04.1 |
|
||||
| unzip | 6.0-25ubuntu1.1 |
|
||||
| upx | 3.95-2build1 |
|
||||
| wget | 1.20.3-1ubuntu2 |
|
||||
| xorriso | 1.5.2-1 |
|
||||
| xvfb | 2:1.20.13-1ubuntu1\~20.04.2 |
|
||||
| xz-utils | 5.2.4-1ubuntu1 |
|
||||
| xvfb | 2:1.20.13-1ubuntu1\~20.04.8 |
|
||||
| xz-utils | 5.2.4-1ubuntu1.1 |
|
||||
| zip | 3.0-11build1 |
|
||||
| zsync | 0.6.2-3ubuntu1 |
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
| Announcements |
|
||||
|-|
|
||||
| [python2.7 will be removed from the images on May 15, 2023](https://github.com/actions/runner-images/issues/7401) |
|
||||
***
|
||||
# Ubuntu 22.04
|
||||
- OS Version: 22.04.2 LTS
|
||||
- Kernel Version: 5.15.0-1037-azure
|
||||
- Image Version: 20230507.1
|
||||
- Systemd version: 249.11-0ubuntu3.9
|
||||
|
||||
## Installed Software
|
||||
|
||||
### Language and Runtime
|
||||
- Bash 5.1.16(1)-release
|
||||
- Clang: 12.0.1, 13.0.1, 14.0.0
|
||||
- Clang-format: 12.0.1, 13.0.1, 14.0.0
|
||||
- Clang-tidy: 12.0.1, 13.0.1, 14.0.0
|
||||
- Dash 0.5.11+git20210903+057cd650a4ed-3build1
|
||||
- GNU C++: 9.5.0, 10.4.0, 11.3.0, 12.1.0
|
||||
- GNU Fortran: 9.5.0, 10.4.0, 11.3.0, 12.1.0
|
||||
- Julia 1.8.5
|
||||
- Kotlin 1.8.21-release-380
|
||||
- Mono 6.12.0.182
|
||||
- MSBuild 16.10.1.31701 (Mono 6.12.0.182)
|
||||
- Node.js 18.16.0
|
||||
- Perl 5.34.0
|
||||
- Python 3.10.6
|
||||
- Python3 3.10.6
|
||||
- Ruby 3.0.2p107
|
||||
- Swift 5.8
|
||||
|
||||
### Package Management
|
||||
- cpan 1.64
|
||||
- Helm 3.11.3
|
||||
- Homebrew 4.0.16
|
||||
- Miniconda 23.3.1
|
||||
- Npm 9.5.1
|
||||
- NuGet 6.3.1.1
|
||||
- Pip 22.0.2
|
||||
- Pip3 22.0.2
|
||||
- Pipx 1.2.0
|
||||
- RubyGems 3.3.5
|
||||
- Vcpkg (build from commit 6a3dd0874)
|
||||
- Yarn 1.22.19
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------------- | ---------------------- |
|
||||
| CONDA | /usr/share/miniconda |
|
||||
| VCPKG_INSTALLATION_ROOT | /usr/local/share/vcpkg |
|
||||
|
||||
#### Homebrew note
|
||||
```
|
||||
Location: /home/linuxbrew
|
||||
Note: Homebrew is pre-installed on image but not added to PATH.
|
||||
run the eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" command
|
||||
to accomplish this.
|
||||
```
|
||||
|
||||
### Project Management
|
||||
- Lerna 6.6.2
|
||||
- Maven 3.8.8
|
||||
|
||||
### Tools
|
||||
- Ansible 2.14.5
|
||||
- apt-fast 1.9.12
|
||||
- AzCopy 10.18.1 - available by `azcopy` and `azcopy10` aliases
|
||||
- Bazel 6.1.2
|
||||
- Bazelisk 1.13.2
|
||||
- Bicep 0.17.1
|
||||
- Buildah 1.23.1
|
||||
- CMake 3.26.3
|
||||
- CodeQL Action Bundles 2.13.0 2.13.1
|
||||
- Docker Amazon ECR Credential Helper 0.7.0
|
||||
- Docker Compose v1 1.29.2
|
||||
- Docker Compose v2 2.17.3+azure-1
|
||||
- Docker-Buildx 0.10.4
|
||||
- Docker-Moby Client 20.10.24+azure-1
|
||||
- Docker-Moby Server 20.10.24+azure-1
|
||||
- Fastlane 2.212.2
|
||||
- Git 2.40.1
|
||||
- Git LFS 3.3.0
|
||||
- Git-ftp 1.6.0
|
||||
- Haveged 1.9.14
|
||||
- Heroku 8.1.3
|
||||
- jq 1.6
|
||||
- Kind 0.18.0
|
||||
- Kubectl 1.27.1
|
||||
- Kustomize 5.0.2
|
||||
- Leiningen 2.10.0
|
||||
- MediaInfo 21.09
|
||||
- Mercurial 6.1.1
|
||||
- Minikube 1.30.1
|
||||
- n 9.1.0
|
||||
- Newman 5.3.2
|
||||
- nvm 0.39.3
|
||||
- OpenSSL 3.0.2-0ubuntu1.9
|
||||
- Packer 1.8.7
|
||||
- Parcel 2.8.3
|
||||
- Podman 3.4.4
|
||||
- Pulumi 3.66.0
|
||||
- R 4.3.0
|
||||
- Skopeo 1.4.1
|
||||
- Sphinx Open Source Search Server 2.2.11
|
||||
- SVN 1.14.1
|
||||
- Terraform 1.4.6
|
||||
- yamllint 1.31.0
|
||||
- yq 4.33.3
|
||||
- zstd 1.5.5
|
||||
|
||||
### CLI Tools
|
||||
- Alibaba Cloud CLI 3.0.163
|
||||
- AWS CLI 2.11.18
|
||||
- AWS CLI Session Manager Plugin 1.2.463.0
|
||||
- AWS SAM CLI 1.82.0
|
||||
- Azure CLI 2.48.1
|
||||
- Azure CLI (azure-devops) 0.26.0
|
||||
- GitHub CLI 2.28.0
|
||||
- Google Cloud SDK 429.0.0
|
||||
- Hub CLI 2.14.2
|
||||
- Netlify CLI 15.0.0
|
||||
- OpenShift CLI 4.12.15
|
||||
- ORAS CLI 1.0.0
|
||||
- Vercel CLI 29.1.1
|
||||
|
||||
### Java
|
||||
| Version | Vendor | Environment Variable |
|
||||
| ------------------- | --------------- | -------------------- |
|
||||
| 8.0.362+9 | Eclipse Temurin | JAVA_HOME_8_X64 |
|
||||
| 11.0.19+7 (default) | Eclipse Temurin | JAVA_HOME_11_X64 |
|
||||
| 17.0.7+7 | Eclipse Temurin | JAVA_HOME_17_X64 |
|
||||
|
||||
### PHP Tools
|
||||
- PHP: 8.1.2
|
||||
- Composer 2.5.5
|
||||
- PHPUnit 8.5.33
|
||||
```
|
||||
Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled.
|
||||
```
|
||||
|
||||
### Haskell Tools
|
||||
- Cabal 3.10.1.0
|
||||
- GHC 9.6.1
|
||||
- GHCup 0.1.19.2
|
||||
- Stack 2.9.3
|
||||
|
||||
### Rust Tools
|
||||
- Cargo 1.69.0
|
||||
- Rust 1.69.0
|
||||
- Rustdoc 1.69.0
|
||||
- Rustup 1.26.0
|
||||
|
||||
#### Packages
|
||||
- Bindgen 0.65.1
|
||||
- Cargo audit 0.17.5
|
||||
- Cargo clippy 0.1.69
|
||||
- Cargo outdated 0.11.2
|
||||
- Cbindgen 0.24.3
|
||||
- Rustfmt 1.5.2
|
||||
|
||||
### Browsers and Drivers
|
||||
- Google Chrome 113.0.5672.63
|
||||
- ChromeDriver 113.0.5672.63
|
||||
- Chromium 113.0.5672.0
|
||||
- Microsoft Edge 113.0.1774.35
|
||||
- Microsoft Edge WebDriver 113.0.1774.35
|
||||
- Selenium server 4.9.0
|
||||
- Mozilla Firefox 113.0
|
||||
- Geckodriver 0.33.0
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------- | ----------------------------------- |
|
||||
| CHROMEWEBDRIVER | /usr/local/share/chrome_driver |
|
||||
| EDGEWEBDRIVER | /usr/local/share/edge_driver |
|
||||
| GECKOWEBDRIVER | /usr/local/share/gecko_driver |
|
||||
| SELENIUM_JAR_PATH | /usr/share/java/selenium-server.jar |
|
||||
|
||||
### .NET Tools
|
||||
- .NET Core SDK: 6.0.408, 7.0.105, 7.0.203
|
||||
- nbgv 3.6.128+518ee610d6
|
||||
|
||||
### Databases
|
||||
- sqlite3 3.37.2
|
||||
|
||||
#### PostgreSQL
|
||||
- PostgreSQL 14.7
|
||||
```
|
||||
User: postgres
|
||||
PostgreSQL service is disabled by default.
|
||||
Use the following command as a part of your job to start the service: 'sudo systemctl start postgresql.service'
|
||||
```
|
||||
|
||||
#### MySQL
|
||||
- MySQL 8.0.32-0ubuntu0.22.04.2
|
||||
```
|
||||
User: root
|
||||
Password: root
|
||||
MySQL service is disabled by default.
|
||||
Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'
|
||||
```
|
||||
|
||||
#### MS SQL
|
||||
- sqlcmd 17.10.0001.1
|
||||
- SqlPackage 16.1.8089.0
|
||||
|
||||
### Cached Tools
|
||||
|
||||
#### Go
|
||||
- 1.18.10
|
||||
- 1.19.9
|
||||
- 1.20.4
|
||||
|
||||
#### Node.js
|
||||
- 14.21.3
|
||||
- 16.20.0
|
||||
- 18.16.0
|
||||
|
||||
#### Python
|
||||
- 3.7.16
|
||||
- 3.8.16
|
||||
- 3.9.16
|
||||
- 3.10.11
|
||||
- 3.11.3
|
||||
|
||||
#### PyPy
|
||||
- 3.7.13 [PyPy 7.3.9]
|
||||
- 3.8.16 [PyPy 7.3.11]
|
||||
- 3.9.16 [PyPy 7.3.11]
|
||||
|
||||
#### Ruby
|
||||
- 3.1.4
|
||||
|
||||
### PowerShell Tools
|
||||
- PowerShell 7.2.11
|
||||
|
||||
#### PowerShell Modules
|
||||
- Az: 9.3.0
|
||||
- MarkdownPS: 1.9
|
||||
- Microsoft.Graph: 1.27.0
|
||||
- Pester: 5.4.1
|
||||
- PSScriptAnalyzer: 1.21.0
|
||||
|
||||
### Web Servers
|
||||
| Name | Version | ConfigFile | ServiceStatus | ListenPort |
|
||||
| ------- | ------- | ------------------------- | ------------- | ---------- |
|
||||
| apache2 | 2.4.52 | /etc/apache2/apache2.conf | inactive | 80 |
|
||||
| nginx | 1.18.0 | /etc/nginx/nginx.conf | inactive | 80 |
|
||||
|
||||
### Android
|
||||
| Package Name | Version |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Android Command Line Tools | 9.0 |
|
||||
| Android Emulator | 32.1.12 |
|
||||
| Android SDK Build-tools | 33.0.0 33.0.1 33.0.2<br>32.0.0<br>31.0.0<br>30.0.0 30.0.1 30.0.2 30.0.3<br>29.0.0 29.0.1 29.0.2 29.0.3<br>28.0.0 28.0.1 28.0.2 28.0.3<br>27.0.0 27.0.1 27.0.2 27.0.3 |
|
||||
| Android SDK Platform-Tools | 34.0.1 |
|
||||
| Android SDK Platforms | android-33-ext5 (rev 1)<br>android-33-ext4 (rev 1)<br>android-33 (rev 2)<br>android-32 (rev 1)<br>android-31 (rev 1)<br>android-30 (rev 3)<br>android-29 (rev 5)<br>android-28 (rev 6)<br>android-27 (rev 3) |
|
||||
| Android SDK Tools | 26.1.1 |
|
||||
| Android Support Repository | 47.0.0 |
|
||||
| CMake | 3.10.2<br>3.18.1<br>3.22.1 |
|
||||
| Google Play services | 49 |
|
||||
| Google Repository | 58 |
|
||||
| NDK | 23.2.8568313<br>24.0.8215888<br>25.2.9519653 (default) |
|
||||
| SDK Patch Applier v4 | 1 |
|
||||
|
||||
#### Environment variables
|
||||
| Name | Value |
|
||||
| ----------------------- | ------------------------------------------- |
|
||||
| ANDROID_HOME | /usr/local/lib/android/sdk |
|
||||
| ANDROID_NDK | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_HOME | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_LATEST_HOME | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_NDK_ROOT | /usr/local/lib/android/sdk/ndk/25.2.9519653 |
|
||||
| ANDROID_SDK_ROOT | /usr/local/lib/android/sdk |
|
||||
|
||||
### Cached Docker images
|
||||
| Repository:Tag | Digest | Created |
|
||||
| ----------------------- | ------------------------------------------------------------------------ | ---------- |
|
||||
| alpine:3.14 | sha256:0f2d5c38dd7a4f4f733e688e3a6733cb5ab1ac6e3cb4603a5dd564e5bfb80eed | 2023-03-29 |
|
||||
| alpine:3.15 | sha256:ecbdce53b2c2f43ab1b19418bcbd3f120a23547d9497030c8d978114512b883e | 2023-03-29 |
|
||||
| alpine:3.16 | sha256:c2b622f6e510a0d25bccaffa9e67b75a6860cb09b74bb58cfc36a9ef4331109f | 2023-03-29 |
|
||||
| alpine:3.17 | sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126 | 2023-03-29 |
|
||||
| buildpack-deps:bullseye | sha256:373587e78550f0918d16b793d1ead24c3f489a14c3af85da1096e2a683908e0c | 2023-05-03 |
|
||||
| buildpack-deps:buster | sha256:bfefe2afb02a82c76d955f2c158b3b5aa96e7afcf262727e8f37ccdea60a39c5 | 2023-05-03 |
|
||||
| debian:10 | sha256:cca6bcced970f7634197ff1821aabb452024eb437958ab98bfc146ece96969c6 | 2023-05-02 |
|
||||
| debian:11 | sha256:63d62ae233b588d6b426b7b072d79d1306bfd02a72bff1fc045b8511cc89ee09 | 2023-05-02 |
|
||||
| moby/buildkit:latest | sha256:d6fa89830c26919acba23c5cafa09df0c3ec1fbde20bb2a15ff349e0795241f4 | 2023-04-20 |
|
||||
| node:14 | sha256:a158d3b9b4e3fa813fa6c8c590b8f0a860e015ad4e59bbce5744d2f6fd8461aa | 2023-04-12 |
|
||||
| node:14-alpine | sha256:434215b487a329c9e867202ff89e704d3a75e554822e07f3e0c0f9e606121b33 | 2023-03-29 |
|
||||
| node:16 | sha256:550f484fc5f314b575f5e397c9e2c71d7f218e59729fcda9ffa7ea1fc825dce7 | 2023-05-04 |
|
||||
| node:16-alpine | sha256:f1657204d3463bce763cefa5b25e48c28af6fe0cdb0f68b354f0f8225ef61be7 | 2023-03-29 |
|
||||
| node:18 | sha256:3f567a26b6b6d601fb2b168d4f987b50697617ead15bfc0e0152e600ac48d0fe | 2023-05-04 |
|
||||
| node:18-alpine | sha256:1ccc70acda680aa4ba47f53e7c40b2d4d6892de74817128e0662d32647dd7f4d | 2023-04-13 |
|
||||
| ubuntu:18.04 | sha256:8aa9c2798215f99544d1ce7439ea9c3a6dfd82de607da1cec3a8a2fae005931b | 2023-03-08 |
|
||||
| ubuntu:20.04 | sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3 | 2023-04-13 |
|
||||
| ubuntu:22.04 | sha256:dfd64a3b4296d8c9b62aa3309984f8620b98d87e47492599ee20739e8eb54fbf | 2023-04-25 |
|
||||
|
||||
### Installed apt packages
|
||||
| Name | Version |
|
||||
| ---------------------- | ----------------------------------- |
|
||||
| acl | 2.3.1-1 |
|
||||
| aria2 | 1.36.0-1 |
|
||||
| autoconf | 2.71-2 |
|
||||
| automake | 1:1.16.5-1.3 |
|
||||
| binutils | 2.38-4ubuntu2.1 |
|
||||
| bison | 2:3.8.2+dfsg-1build1 |
|
||||
| brotli | 1.0.9-2build6 |
|
||||
| build-essential | 12.9ubuntu3 |
|
||||
| bzip2 | 1.0.8-5build1 |
|
||||
| coreutils | 8.32-4.1ubuntu1 |
|
||||
| curl | 7.81.0-1ubuntu1.10 |
|
||||
| dbus | 1.12.20-2ubuntu4.1 |
|
||||
| dnsutils | 1:9.18.12-0ubuntu0.22.04.1 |
|
||||
| dpkg | 1.21.1ubuntu2.1 |
|
||||
| fakeroot | 1.28-1ubuntu1 |
|
||||
| file | 1:5.41-3 |
|
||||
| flex | 2.6.4-8build2 |
|
||||
| fonts-noto-color-emoji | 2.038-0ubuntu1 |
|
||||
| ftp | 20210827-4build1 |
|
||||
| gnupg2 | 2.2.27-3ubuntu2.1 |
|
||||
| haveged | 1.9.14-1ubuntu1 |
|
||||
| imagemagick | 8:6.9.11.60+dfsg-1.3ubuntu0.22.04.3 |
|
||||
| iproute2 | 5.15.0-1ubuntu2 |
|
||||
| iputils-ping | 3:20211215-1 |
|
||||
| jq | 1.6-2.1ubuntu3 |
|
||||
| lib32z1 | 1:1.2.11.dfsg-2ubuntu9.2 |
|
||||
| libc++-dev | 1:14.0-55\~exp2 |
|
||||
| libc++abi-dev | 1:14.0-55\~exp2 |
|
||||
| libcurl4 | 7.81.0-1ubuntu1.10 |
|
||||
| libgbm-dev | 22.2.5-0ubuntu0.1\~22.04.1 |
|
||||
| libgconf-2-4 | 3.2.6-7ubuntu2 |
|
||||
| libgsl-dev | 2.7.1+dfsg-3 |
|
||||
| libgtk-3-0 | 3.24.33-1ubuntu2 |
|
||||
| libmagic-dev | 1:5.41-3 |
|
||||
| libmagickcore-dev | 8:6.9.11.60+dfsg-1.3ubuntu0.22.04.3 |
|
||||
| libmagickwand-dev | 8:6.9.11.60+dfsg-1.3ubuntu0.22.04.3 |
|
||||
| libsecret-1-dev | 0.20.5-2 |
|
||||
| libsqlite3-dev | 3.37.2-2ubuntu0.1 |
|
||||
| libssl-dev | 3.0.2-0ubuntu1.9 |
|
||||
| libtool | 2.4.6-15build2 |
|
||||
| libunwind8 | 1.3.2-2build2 |
|
||||
| libxkbfile-dev | 1:1.1.0-1build3 |
|
||||
| libxss1 | 1:1.2.3-1build2 |
|
||||
| libyaml-dev | 0.2.2-1build2 |
|
||||
| locales | 2.35-0ubuntu3.1 |
|
||||
| lz4 | 1.9.3-2build2 |
|
||||
| m4 | 1.4.18-5ubuntu2 |
|
||||
| mediainfo | 22.03-1 |
|
||||
| mercurial | 6.1.1-1ubuntu1 |
|
||||
| net-tools | 1.60+git20181103.0eebece-1ubuntu5 |
|
||||
| netcat | 1.218-4ubuntu1 |
|
||||
| openssh-client | 1:8.9p1-3ubuntu0.1 |
|
||||
| p7zip-full | 16.02+dfsg-8 |
|
||||
| p7zip-rar | 16.02-3build1 |
|
||||
| parallel | 20210822+ds-2 |
|
||||
| pass | 1.7.4-5 |
|
||||
| patchelf | 0.14.3-1 |
|
||||
| pkg-config | 0.29.2-1ubuntu3 |
|
||||
| pollinate | 4.33-3ubuntu2 |
|
||||
| python-is-python3 | 3.9.2-2 |
|
||||
| rpm | 4.17.0+dfsg1-4build1 |
|
||||
| rsync | 3.2.7-0ubuntu0.22.04.2 |
|
||||
| shellcheck | 0.8.0-2 |
|
||||
| sphinxsearch | 2.2.11-8 |
|
||||
| sqlite3 | 3.37.2-2ubuntu0.1 |
|
||||
| ssh | 1:8.9p1-3ubuntu0.1 |
|
||||
| sshpass | 1.09-1 |
|
||||
| subversion | 1.14.1-3ubuntu0.22.04.1 |
|
||||
| sudo | 1.9.9-1ubuntu2.4 |
|
||||
| swig | 4.0.2-1ubuntu1 |
|
||||
| tar | 1.34+dfsg-1ubuntu0.1.22.04.1 |
|
||||
| telnet | 0.17-44build1 |
|
||||
| texinfo | 6.8-4build1 |
|
||||
| time | 1.9-0.1build2 |
|
||||
| tk | 8.6.11+1build2 |
|
||||
| tzdata | 2023c-0ubuntu0.22.04.1 |
|
||||
| unzip | 6.0-26ubuntu3.1 |
|
||||
| upx | 3.96-3 |
|
||||
| wget | 1.21.2-2ubuntu1 |
|
||||
| xorriso | 1.5.4-2 |
|
||||
| xvfb | 2:21.1.4-2ubuntu1.7\~22.04.1 |
|
||||
| xz-utils | 5.2.5-2ubuntu1 |
|
||||
| zip | 3.0-12build2 |
|
||||
| zsync | 0.6.2-3ubuntu1 |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Name of pool supported by this image
|
||||
POOL_NAME="Ubuntu 1804"
|
||||
POOL_NAME="Ubuntu 2204"
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Enable user session on boot, not on login
|
||||
UserId=$(cut -d: -f3 /etc/passwd | tail -1)
|
||||
loginctl enable-linger $UserId
|
||||
@@ -166,9 +166,9 @@ function Get-AndroidNDKVersions {
|
||||
}
|
||||
|
||||
function Build-AndroidEnvironmentTable {
|
||||
$androidVersions = Get-Item env:ANDROID_*
|
||||
$androidVersions = Get-Item env:ANDROID_*
|
||||
|
||||
$shouldResolveLink = 'ANDROID_NDK_PATH', 'ANDROID_NDK_HOME', 'ANDROID_NDK_ROOT', 'ANDROID_NDK_LATEST_HOME'
|
||||
$shouldResolveLink = 'ANDROID_NDK', 'ANDROID_NDK_HOME', 'ANDROID_NDK_ROOT', 'ANDROID_NDK_LATEST_HOME'
|
||||
return $androidVersions | Sort-Object -Property Name | ForEach-Object {
|
||||
[PSCustomObject] @{
|
||||
"Name" = $_.Name
|
||||
|
||||
@@ -1,52 +1,61 @@
|
||||
function Get-ChromeVersion {
|
||||
$googleChromeVersion = google-chrome --version | Take-OutputPart -Part 2
|
||||
return "Google Chrome $googleChromeVersion"
|
||||
return $googleChromeVersion
|
||||
}
|
||||
|
||||
function Get-ChromeDriverVersion {
|
||||
$chromeDriverVersion = chromedriver --version | Take-OutputPart -Part 1
|
||||
return "ChromeDriver $chromeDriverVersion"
|
||||
return $chromeDriverVersion
|
||||
}
|
||||
|
||||
function Get-FirefoxVersion {
|
||||
$firefoxVersion = firefox --version
|
||||
$firefoxVersion = $(firefox --version) | Take-OutputPart -Part 2
|
||||
return $firefoxVersion
|
||||
}
|
||||
|
||||
function Get-GeckodriverVersion {
|
||||
$geckodriverVersion = geckodriver --version | Select-Object -First 1 | Take-OutputPart -Part 1
|
||||
return "Geckodriver $geckodriverVersion"
|
||||
return $geckodriverVersion
|
||||
}
|
||||
|
||||
function Get-ChromiumVersion {
|
||||
$chromiumVersion = chromium-browser --version | Take-OutputPart -Part 0,1
|
||||
$chromiumVersion = chromium-browser --version | Take-OutputPart -Part 1
|
||||
return $chromiumVersion
|
||||
}
|
||||
|
||||
function Get-EdgeVersion {
|
||||
$edgeVersion = (microsoft-edge --version).Trim() | Take-OutputPart -Part 2
|
||||
return $edgeVersion
|
||||
}
|
||||
|
||||
function Get-EdgeDriverVersion {
|
||||
$edgeDriverVersion = msedgedriver --version | Take-OutputPart -Part 3
|
||||
return $edgeDriverVersion
|
||||
}
|
||||
|
||||
function Get-SeleniumVersion {
|
||||
$seleniumBinaryName = Get-ToolsetValue "selenium.binary_name"
|
||||
$fullSeleniumVersion = (Get-ChildItem "/usr/share/java/${seleniumBinaryName}-*").Name -replace "${seleniumBinaryName}-"
|
||||
return "Selenium server $fullSeleniumVersion"
|
||||
return $fullSeleniumVersion
|
||||
}
|
||||
|
||||
function Build-BrowserWebdriversEnvironmentTable {
|
||||
return @(
|
||||
@{
|
||||
[PSCustomObject] @{
|
||||
"Name" = "CHROMEWEBDRIVER"
|
||||
"Value" = $env:CHROMEWEBDRIVER
|
||||
},
|
||||
@{
|
||||
[PSCustomObject] @{
|
||||
"Name" = "EDGEWEBDRIVER"
|
||||
"Value" = $env:EDGEWEBDRIVER
|
||||
},
|
||||
[PSCustomObject] @{
|
||||
"Name" = "GECKOWEBDRIVER"
|
||||
"Value" = $env:GECKOWEBDRIVER
|
||||
},
|
||||
@{
|
||||
[PSCustomObject] @{
|
||||
"Name" = "SELENIUM_JAR_PATH"
|
||||
"Value" = $env:SELENIUM_JAR_PATH
|
||||
}
|
||||
) | ForEach-Object {
|
||||
[PSCustomObject] @{
|
||||
"Name" = $_.Name
|
||||
"Value" = $_.Value
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,37 +27,3 @@ function Get-ToolcacheGoVersions {
|
||||
$toolcachePath = Join-Path $env:AGENT_TOOLSDIRECTORY "go"
|
||||
return Get-ChildItem $toolcachePath -Name | Sort-Object { [Version]$_ }
|
||||
}
|
||||
|
||||
function Build-GoEnvironmentTable {
|
||||
return Get-CachedToolInstances -Name "go" -VersionCommand "version" | ForEach-Object {
|
||||
$Version = [System.Version]($_.Version -Split(" "))[0]
|
||||
$Name = "GOROOT_$($Version.major)_$($Version.minor)_X64"
|
||||
$Value = (Get-Item env:\$Name).Value
|
||||
[PSCustomObject] @{
|
||||
"Name" = $Name
|
||||
"Value" = (Get-Item env:\$Name).Value
|
||||
"Architecture" = $_. Architecture
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Build-CachedToolsSection {
|
||||
$output = ""
|
||||
|
||||
$output += New-MDHeader "Go" -Level 4
|
||||
$output += New-MDList -Lines (Get-ToolcacheGoVersions) -Style Unordered
|
||||
|
||||
$output += New-MDHeader "Node.js" -Level 4
|
||||
$output += New-MDList -Lines (Get-ToolcacheNodeVersions) -Style Unordered
|
||||
|
||||
$output += New-MDHeader "PyPy" -Level 4
|
||||
$output += New-MDList -Lines (Get-ToolcachePyPyVersions) -Style Unordered
|
||||
|
||||
$output += New-MDHeader "Python" -Level 4
|
||||
$output += New-MDList -Lines (Get-ToolcachePythonVersions) -Style Unordered
|
||||
|
||||
$output += New-MDHeader "Ruby" -Level 4
|
||||
$output += New-MDList -Lines (Get-ToolcacheRubyVersions) -Style Unordered
|
||||
|
||||
return $output
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
function Get-BashVersion {
|
||||
$version = bash -c 'echo ${BASH_VERSION}'
|
||||
return "Bash $version"
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-DashVersion {
|
||||
$version = dpkg-query -W -f '${Version}' dash
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-CPPVersions {
|
||||
@@ -8,7 +13,7 @@ function Get-CPPVersions {
|
||||
$cppVersions = $result.Output | Where-Object { $_ -match "g\+\+-\d+"} | ForEach-Object {
|
||||
& $_.Split("/")[0] --version | Select-Object -First 1 | Take-OutputPart -Part 3
|
||||
} | Sort-Object {[Version]$_}
|
||||
return "GNU C++ " + ($cppVersions -Join ", ")
|
||||
return $cppVersions
|
||||
}
|
||||
|
||||
function Get-FortranVersions {
|
||||
@@ -17,227 +22,212 @@ function Get-FortranVersions {
|
||||
$_ -match "now (?<version>\d+\.\d+\.\d+)-" | Out-Null
|
||||
$Matches.version
|
||||
} | Sort-Object {[Version]$_}
|
||||
return "GNU Fortran " + ($fortranVersions -Join ", ")
|
||||
return $fortranVersions
|
||||
}
|
||||
|
||||
function Get-ClangToolVersions {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string] $ToolName,
|
||||
[string] $VersionLineMatcher = "${ToolName} version",
|
||||
[string] $VersionPattern = "\d+\.\d+\.\d+)-"
|
||||
)
|
||||
|
||||
$result = Get-CommandResult "apt list --installed" -Multiline
|
||||
$toolVersions = $result.Output | Where-Object { $_ -match "^${ToolName}-\d+"} | ForEach-Object {
|
||||
$clangCommand = ($_ -Split "/")[0]
|
||||
Invoke-Expression "$clangCommand --version" | Where-Object { $_ -match "${ToolName} version" } | ForEach-Object {
|
||||
$_ -match "${ToolName} version (?<version>${VersionPattern}" | Out-Null
|
||||
Invoke-Expression "$clangCommand --version" | Where-Object { $_ -match "${VersionLineMatcher}" } | ForEach-Object {
|
||||
$_ -match "${VersionLineMatcher} (?<version>${VersionPattern}" | Out-Null
|
||||
$Matches.version
|
||||
}
|
||||
} | Sort-Object {[Version]$_}
|
||||
|
||||
return $toolVersions -Join ", "
|
||||
return $toolVersions
|
||||
}
|
||||
|
||||
function Get-ClangVersions {
|
||||
$clangVersions = Get-ClangToolVersions -ToolName "clang"
|
||||
return "Clang " + $clangVersions
|
||||
}
|
||||
|
||||
function Get-ClangFormatVersions {
|
||||
$clangFormatVersions = Get-ClangToolVersions -ToolName "clang-format"
|
||||
return "Clang-format " + $clangFormatVersions
|
||||
function Get-ClangTidyVersions {
|
||||
return Get-ClangToolVersions -ToolName "clang-tidy" -VersionLineMatcher "LLVM version" -VersionPattern "\d+\.\d+\.\d+)"
|
||||
}
|
||||
|
||||
|
||||
function Get-ErlangVersion {
|
||||
$erlangVersion = (erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), ''OTP_VERSION''])), io:fwrite(Version), halt().' -noshell)
|
||||
$shellVersion = (erl -eval 'erlang:display(erlang:system_info(version)), halt().' -noshell).Trim('"')
|
||||
return "Erlang $erlangVersion (Eshell $shellVersion)"
|
||||
return "$erlangVersion (Eshell $shellVersion)"
|
||||
}
|
||||
|
||||
function Get-ErlangRebar3Version {
|
||||
$result = Get-CommandResult "rebar3 --version"
|
||||
$result.Output -match "rebar (?<version>(\d+.){2}\d+)" | Out-Null
|
||||
$rebarVersion = $Matches.version
|
||||
return "Erlang rebar3 $rebarVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-MonoVersion {
|
||||
$monoVersion = mono --version | Out-String | Take-OutputPart -Part 4
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "mono"
|
||||
return "Mono $monoVersion (apt source repository: $aptSourceRepo)"
|
||||
return $monoVersion
|
||||
}
|
||||
|
||||
function Get-MsbuildVersion {
|
||||
$msbuildVersion = msbuild -version | Select-Object -Last 1
|
||||
$result = Select-String -Path (Get-Command msbuild).Source -Pattern "msbuild"
|
||||
$result -match "(?<path>\/\S*\.dll)" | Out-Null
|
||||
$msbuildPath = $Matches.path
|
||||
return "MSBuild $msbuildVersion (from $msbuildPath)"
|
||||
$monoVersion = Get-MonoVersion
|
||||
return "$msbuildVersion (Mono $monoVersion)"
|
||||
}
|
||||
|
||||
function Get-NuGetVersion {
|
||||
$nugetVersion = nuget help | Select-Object -First 1 | Take-OutputPart -Part 2
|
||||
return $nugetVersion
|
||||
}
|
||||
|
||||
function Get-NodeVersion {
|
||||
$nodeVersion = $(node --version).Substring(1)
|
||||
return "Node $nodeVersion"
|
||||
return $nodeVersion
|
||||
}
|
||||
|
||||
function Get-OpensslVersion {
|
||||
return $(openssl version)
|
||||
return $(dpkg-query -W -f '${Version}' openssl)
|
||||
}
|
||||
|
||||
function Get-PerlVersion {
|
||||
$version = $(perl -e 'print substr($^V,1)')
|
||||
return "Perl $version"
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-PythonVersion {
|
||||
$result = Get-CommandResult "python --version"
|
||||
$version = $result.Output | Take-OutputPart -Part 1
|
||||
return "Python $version"
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-Python3Version {
|
||||
$result = Get-CommandResult "python3 --version"
|
||||
$version = $result.Output | Take-OutputPart -Part 1
|
||||
return "Python3 $version"
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-PowershellVersion {
|
||||
return $(pwsh --version)
|
||||
return $(pwsh --version) | Take-OutputPart -Part 1
|
||||
}
|
||||
|
||||
function Get-RubyVersion {
|
||||
$rubyVersion = ruby --version | Out-String | Take-OutputPart -Part 1
|
||||
return "Ruby $rubyVersion"
|
||||
return $rubyVersion
|
||||
}
|
||||
|
||||
function Get-SwiftVersion {
|
||||
$swiftVersion = swift --version | Out-String | Take-OutputPart -Part 2
|
||||
return "Swift $swiftVersion"
|
||||
return $swiftVersion
|
||||
}
|
||||
|
||||
function Get-KotlinVersion {
|
||||
$kotlinVersion = kotlin -version | Out-String | Take-OutputPart -Part 2
|
||||
return "Kotlin $kotlinVersion"
|
||||
return $kotlinVersion
|
||||
}
|
||||
|
||||
function Get-JuliaVersion {
|
||||
$juliaVersion = julia --version | Take-OutputPart -Part 2
|
||||
return "Julia $juliaVersion"
|
||||
return $juliaVersion
|
||||
}
|
||||
|
||||
function Get-LernaVersion {
|
||||
$version = lerna -v
|
||||
return "Lerna $version"
|
||||
return $version
|
||||
}
|
||||
|
||||
function Get-HomebrewVersion {
|
||||
$result = Get-CommandResult "brew -v"
|
||||
$result = Get-CommandResult "/home/linuxbrew/.linuxbrew/bin/brew -v"
|
||||
$result.Output -match "Homebrew (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$version = $Matches.version
|
||||
return "Homebrew $version"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-CpanVersion {
|
||||
$result = Get-CommandResult "cpan --version" -ExpectExitCode @(25, 255)
|
||||
$result.Output -match "version (?<version>\d+\.\d+) " | Out-Null
|
||||
$cpanVersion = $Matches.version
|
||||
return "cpan $cpanVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-GemVersion {
|
||||
$result = Get-CommandResult "gem --version"
|
||||
$result.Output -match "(?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$gemVersion = $Matches.version
|
||||
return "RubyGems $gemVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-MinicondaVersion {
|
||||
$condaVersion = conda --version
|
||||
return "Mini$condaVersion"
|
||||
$condaVersion = conda --version | Take-OutputPart -Part 1
|
||||
return $condaVersion
|
||||
}
|
||||
|
||||
function Get-HelmVersion {
|
||||
$(helm version) -match 'Version:"v(?<version>\d+\.\d+\.\d+)"' | Out-Null
|
||||
$helmVersion = $Matches.version
|
||||
return "Helm $helmVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-NpmVersion {
|
||||
$npmVersion = npm --version
|
||||
return "Npm $npmVersion"
|
||||
return $npmVersion
|
||||
}
|
||||
|
||||
function Get-YarnVersion {
|
||||
$yarnVersion = yarn --version
|
||||
return "Yarn $yarnVersion"
|
||||
return $yarnVersion
|
||||
}
|
||||
|
||||
function Get-ParcelVersion {
|
||||
$parcelVersion = parcel --version
|
||||
return "Parcel $parcelVersion"
|
||||
return $parcelVersion
|
||||
}
|
||||
|
||||
function Get-PipVersion {
|
||||
$result = Get-CommandResult "pip --version"
|
||||
$result.Output -match "pip (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$pipVersion = $Matches.version
|
||||
return "Pip $pipVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-Pip3Version {
|
||||
$result = Get-CommandResult "pip3 --version"
|
||||
$result.Output -match "pip (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$pipVersion = $Matches.version
|
||||
return "Pip3 $pipVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-VcpkgVersion {
|
||||
$result = Get-CommandResult "vcpkg version"
|
||||
$result.Output -match "version (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$vcpkgVersion = $Matches.version
|
||||
$commitId = git -C "/usr/local/share/vcpkg" rev-parse --short HEAD
|
||||
return "Vcpkg $vcpkgVersion (build from master \<$commitId>)"
|
||||
return "(build from commit $commitId)"
|
||||
}
|
||||
|
||||
function Get-AntVersion {
|
||||
$result = ant -version | Out-String
|
||||
$result -match "version (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$antVersion = $Matches.version
|
||||
return "Ant $antVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-GradleVersion {
|
||||
$gradleVersion = (gradle -v) -match "^Gradle \d" | Take-OutputPart -Part 1
|
||||
return "Gradle $gradleVersion"
|
||||
return $gradleVersion
|
||||
}
|
||||
|
||||
function Get-MavenVersion {
|
||||
$result = mvn -version | Out-String
|
||||
$result -match "Apache Maven (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$mavenVersion = $Matches.version
|
||||
return "Maven $mavenVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-SbtVersion {
|
||||
$result = Get-CommandResult "sbt -version"
|
||||
$result.Output -match "sbt script version: (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$sbtVersion = $Matches.version
|
||||
return "Sbt $sbtVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-PHPVersions {
|
||||
$result = Get-CommandResult "apt list --installed" -Multiline
|
||||
return $result.Output | Where-Object { $_ -match "^php\d+\.\d+/"} | ForEach-Object {
|
||||
$_ -match "now (?<version>\d+\.\d+\.\d+)-" | Out-Null
|
||||
$_ -match "now (\d+:)?(?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$Matches.version
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ComposerVersion {
|
||||
$(composer --version) -match "Composer version (?<version>\d+\.\d+\.\d+)\s" | Out-Null
|
||||
return $Matches.version
|
||||
$composerVersion = (composer --version) -replace " version" | Take-OutputPart -Part 1
|
||||
return $composerVersion
|
||||
}
|
||||
|
||||
function Get-PHPUnitVersion {
|
||||
@@ -245,60 +235,24 @@ function Get-PHPUnitVersion {
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Build-PHPTable {
|
||||
$php = @{
|
||||
"Tool" = "PHP"
|
||||
"Version" = "$(Get-PHPVersions -Join '<br>')"
|
||||
}
|
||||
$composer = @{
|
||||
"Tool" = "Composer"
|
||||
"Version" = Get-ComposerVersion
|
||||
}
|
||||
$phpunit = @{
|
||||
"Tool" = "PHPUnit"
|
||||
"Version" = Get-PHPUnitVersion
|
||||
}
|
||||
return @($php, $composer, $phpunit) | ForEach-Object {
|
||||
[PSCustomObject] @{
|
||||
"Tool" = $_.Tool
|
||||
"Version" = $_.Version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Build-PHPSection {
|
||||
$output = ""
|
||||
$output += New-MDHeader "PHP" -Level 3
|
||||
$output += Build-PHPTable | New-MDTable
|
||||
$output += New-MDCode -Lines @(
|
||||
"Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled."
|
||||
)
|
||||
|
||||
return $output
|
||||
}
|
||||
|
||||
function Get-GHCVersion {
|
||||
$(ghc --version) -match "version (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$ghcVersion = $Matches.version
|
||||
return "GHC $ghcVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-GHCupVersion {
|
||||
$(ghcup --version) -match "version v(?<version>\d+(\.\d+){2,})" | Out-Null
|
||||
$ghcVersion = $Matches.version
|
||||
return "GHCup $ghcVersion"
|
||||
$(ghcup --version) -match "version (?<version>\d+(\.\d+){2,})" | Out-Null
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-CabalVersion {
|
||||
$(cabal --version | Out-String) -match "cabal-install version (?<version>\d+\.\d+\.\d+\.\d+)" | Out-Null
|
||||
$cabalVersion = $Matches.version
|
||||
return "Cabal $cabalVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-StackVersion {
|
||||
$(stack --version | Out-String) -match "Version (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$stackVersion = $Matches.version
|
||||
return "Stack $stackVersion"
|
||||
return $Matches.version
|
||||
}
|
||||
|
||||
function Get-AzModuleVersions {
|
||||
@@ -311,38 +265,40 @@ function Get-AzModuleVersions {
|
||||
}
|
||||
|
||||
function Get-PowerShellModules {
|
||||
$modules = (Get-ToolsetContent).powershellModules.name
|
||||
[Array] $result = @()
|
||||
|
||||
$psModules = Get-Module -Name $modules -ListAvailable | Sort-Object Name | Group-Object Name
|
||||
$psModules | ForEach-Object {
|
||||
$moduleName = $_.Name
|
||||
$moduleVersions = ($_.group.Version | Sort-Object -Unique) -join '<br>'
|
||||
|
||||
[PSCustomObject]@{
|
||||
Module = $moduleName
|
||||
Version = $moduleVersions
|
||||
}
|
||||
[Array] $azureInstalledModules = Get-ChildItem -Path "/usr/share/az_*" -Directory | ForEach-Object { $_.Name.Split("_")[1] }
|
||||
if ($azureInstalledModules.Count -gt 0) {
|
||||
$result += [ToolVersionsListNode]::new("Az", $azureInstalledModules, "^\d+\.\d+", "Inline")
|
||||
}
|
||||
|
||||
[Array] $azureCachedModules = Get-ChildItem /usr/share/az_*.zip -File | ForEach-Object { $_.Name.Split("_")[1] }
|
||||
if ($azureCachedModules.Count -gt 0) {
|
||||
$result += [ToolVersionsListNode]::new("Az (Cached)", $azureCachedModules, "^\d+\.\d+", "Inline")
|
||||
}
|
||||
|
||||
(Get-ToolsetContent).powershellModules.name | ForEach-Object {
|
||||
$moduleName = $_
|
||||
$moduleVersions = Get-Module -Name $moduleName -ListAvailable | Select-Object -ExpandProperty Version | Sort-Object -Unique
|
||||
$result += [ToolVersionsListNode]::new($moduleName, $moduleVersions, "^\d+", "Inline")
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
function Get-DotNetCoreSdkVersions {
|
||||
$unsortedDotNetCoreSdkVersion = dotnet --list-sdks list | ForEach-Object { $_ | Take-OutputPart -Part 0 }
|
||||
$dotNetCoreSdkVersion = $unsortedDotNetCoreSdkVersion -join " "
|
||||
$dotNetCoreSdkVersion = dotnet --list-sdks list | ForEach-Object { $_ | Take-OutputPart -Part 0 }
|
||||
return $dotNetCoreSdkVersion
|
||||
}
|
||||
|
||||
function Get-DotnetTools {
|
||||
$env:PATH = "/etc/skel/.dotnet/tools:$($env:PATH)"
|
||||
|
||||
$dotnetTools = (Get-ToolsetContent).dotnet.tools
|
||||
|
||||
$toolsList = @()
|
||||
|
||||
ForEach ($dotnetTool in $dotnetTools) {
|
||||
$toolsList += $dotnetTool.name + " " + (Invoke-Expression $dotnetTool.getversion)
|
||||
return $dotnetTools | ForEach-Object {
|
||||
$version = Invoke-Expression $_.getversion
|
||||
return [ToolVersionNode]::new($_.name, $version)
|
||||
}
|
||||
|
||||
return $toolsList
|
||||
}
|
||||
|
||||
function Get-CachedDockerImages {
|
||||
@@ -385,39 +341,24 @@ function Get-AptPackages {
|
||||
function Get-PipxVersion {
|
||||
$result = (Get-CommandResult "pipx --version").Output
|
||||
$result -match "(?<version>\d+\.\d+\.\d+\.?\d*)" | Out-Null
|
||||
$pipxVersion = $Matches.Version
|
||||
return "Pipx $pipxVersion"
|
||||
}
|
||||
|
||||
function Get-GraalVMVersion {
|
||||
$version = & "$env:GRAALVM_11_ROOT\bin\java" --version | Select-String -Pattern "GraalVM" | Take-OutputPart -Part 5,6
|
||||
return $version
|
||||
}
|
||||
|
||||
function Build-GraalVMTable {
|
||||
$version = Get-GraalVMVersion
|
||||
$envVariables = "GRAALVM_11_ROOT"
|
||||
|
||||
return [PSCustomObject] @{
|
||||
"Version" = $version
|
||||
"Environment variables" = $envVariables
|
||||
}
|
||||
return $Matches.Version
|
||||
}
|
||||
|
||||
function Build-PackageManagementEnvironmentTable {
|
||||
return @(
|
||||
@{
|
||||
[PSCustomObject] @{
|
||||
"Name" = "CONDA"
|
||||
"Value" = $env:CONDA
|
||||
},
|
||||
@{
|
||||
[PSCustomObject] @{
|
||||
"Name" = "VCPKG_INSTALLATION_ROOT"
|
||||
"Value" = $env:VCPKG_INSTALLATION_ROOT
|
||||
}
|
||||
) | ForEach-Object {
|
||||
[PSCustomObject] @{
|
||||
"Name" = $_.Name
|
||||
"Value" = $_.Value
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function Get-SystemdVersion {
|
||||
$matches = [regex]::Matches((systemctl --version | head -n 1), "\((.*?)\)")
|
||||
$result = foreach ($match in $matches) {$match.Groups[1].Value}
|
||||
return $result
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
function Get-PostgreSqlVersion {
|
||||
$postgreSQLVersion = psql --version | Take-OutputPart -Part 2
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "postgresql"
|
||||
return "PostgreSQL $postgreSQLVersion (apt source repository: $aptSourceRepo)"
|
||||
return $postgreSQLVersion
|
||||
}
|
||||
|
||||
function Get-MongoDbVersion {
|
||||
$mongoDBVersion = mongod --version | Select-Object -First 1 | Take-OutputPart -Part 2 -Delimiter "v"
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "mongodb"
|
||||
return "MongoDB $mongoDBVersion (apt source repository: $aptSourceRepo)"
|
||||
return $mongoDBVersion
|
||||
}
|
||||
|
||||
function Get-SqliteVersion {
|
||||
$sqliteVersion = sqlite3 --version | Take-OutputPart -Part 0
|
||||
return "sqlite3 $sqliteVersion"
|
||||
return $sqliteVersion
|
||||
}
|
||||
|
||||
function Get-MySQLVersion {
|
||||
$mySQLVersion = mysqld --version | Take-OutputPart -Part 2
|
||||
if (-not (Test-IsUbuntu20)) {
|
||||
$mySQLVersion = $mySQLVersion | Take-OutputPart -Part 0 -Delimiter "-"
|
||||
}
|
||||
return "MySQL $mySQLVersion"
|
||||
return $mySQLVersion
|
||||
}
|
||||
|
||||
function Get-SQLCmdVersion {
|
||||
$sqlcmdVersion = sqlcmd -? | Select-String -Pattern "Version" | Take-OutputPart -Part 1
|
||||
return "sqlcmd $sqlcmdVersion"
|
||||
return $sqlcmdVersion
|
||||
}
|
||||
|
||||
function Get-SqlPackageVersion {
|
||||
$sqlPackageVersion = sqlpackage /version
|
||||
return "SqlPackage $sqlPackageVersion"
|
||||
return $sqlPackageVersion
|
||||
}
|
||||
|
||||
function Build-PostgreSqlSection {
|
||||
$node = [HeaderNode]::new("PostgreSQL")
|
||||
$node.AddToolVersion("PostgreSQL", $(Get-PostgreSqlVersion))
|
||||
$node.AddNote(@(
|
||||
"User: postgres",
|
||||
"PostgreSQL service is disabled by default.",
|
||||
"Use the following command as a part of your job to start the service: 'sudo systemctl start postgresql.service'"
|
||||
) -join "`n")
|
||||
|
||||
return $node
|
||||
}
|
||||
|
||||
function Build-MySQLSection {
|
||||
$output = ""
|
||||
$node = [HeaderNode]::new("MySQL")
|
||||
$node.AddToolVersion("MySQL", $(Get-MySQLVersion))
|
||||
$node.AddNote(@(
|
||||
"User: root",
|
||||
"Password: root",
|
||||
"MySQL service is disabled by default.",
|
||||
"Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'"
|
||||
) -join "`n")
|
||||
|
||||
$output += New-MDHeader "MySQL" -Level 4
|
||||
$output += New-MDList -Style Unordered -Lines @(
|
||||
(Get-MySQLVersion ),
|
||||
"MySQL Server (user:root password:root)"
|
||||
)
|
||||
$output += New-MDCode -Lines @(
|
||||
"MySQL service is disabled by default. Use the following command as a part of your job to start the service: 'sudo systemctl start mysql.service'"
|
||||
)
|
||||
|
||||
return $output
|
||||
return $node
|
||||
}
|
||||
|
||||
function Build-MSSQLToolsSection {
|
||||
$output = ""
|
||||
|
||||
$output += New-MDHeader "MS SQL Server Client Tools" -Level 4
|
||||
$output += New-MDList -Style Unordered -Lines @(
|
||||
(Get-SQLCmdVersion),
|
||||
(Get-SqlPackageVersion)
|
||||
)
|
||||
|
||||
return $output
|
||||
$node = [HeaderNode]::new("MS SQL")
|
||||
$node.AddToolVersion("sqlcmd", $(Get-SQLCmdVersion))
|
||||
$node.AddToolVersion("SqlPackage", $(Get-SqlPackageVersion))
|
||||
return $node
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using module ./software-report-base/SoftwareReport.psm1
|
||||
using module ./software-report-base/SoftwareReport.Nodes.psm1
|
||||
|
||||
param (
|
||||
[Parameter(Mandatory)][string]
|
||||
$OutputDirectory
|
||||
@@ -7,7 +10,6 @@ $global:ErrorActionPreference = "Stop"
|
||||
$global:ErrorView = "NormalView"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
Import-Module MarkdownPS
|
||||
Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Android.psm1") -DisableNameChecking
|
||||
Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Browsers.psm1") -DisableNameChecking
|
||||
Import-Module (Join-Path $PSScriptRoot "SoftwareReport.CachedTools.psm1") -DisableNameChecking
|
||||
@@ -23,261 +25,219 @@ Import-Module (Join-Path $PSScriptRoot "SoftwareReport.WebServers.psm1") -Disabl
|
||||
# Restore file owner in user profile
|
||||
Restore-UserOwner
|
||||
|
||||
$markdown = ""
|
||||
# Software report
|
||||
$softwareReport = [SoftwareReport]::new("Ubuntu $(Get-OSVersionShort)")
|
||||
$softwareReport.Root.AddToolVersion("OS Version:", $(Get-OSVersionFull))
|
||||
$softwareReport.Root.AddToolVersion("Kernel Version:", $(Get-KernelVersion))
|
||||
$softwareReport.Root.AddToolVersion("Image Version:", $env:IMAGE_VERSION)
|
||||
$softwareReport.Root.AddToolVersion("Systemd version:", $(Get-SystemdVersion))
|
||||
|
||||
$OSName = Get-OSName
|
||||
$markdown += New-MDHeader "$OSName" -Level 1
|
||||
|
||||
$kernelVersion = Get-KernelVersion
|
||||
$markdown += New-MDList -Style Unordered -Lines @(
|
||||
"$kernelVersion"
|
||||
"Image Version: $env:IMAGE_VERSION"
|
||||
)
|
||||
|
||||
$markdown += New-MDHeader "Installed Software" -Level 2
|
||||
$markdown += New-MDHeader "Language and Runtime" -Level 3
|
||||
|
||||
$runtimesList = @(
|
||||
(Get-BashVersion),
|
||||
(Get-CPPVersions),
|
||||
(Get-FortranVersions),
|
||||
(Get-ErlangVersion),
|
||||
(Get-ErlangRebar3Version),
|
||||
(Get-MonoVersion),
|
||||
(Get-MsbuildVersion),
|
||||
(Get-NodeVersion),
|
||||
(Get-PerlVersion),
|
||||
(Get-PythonVersion),
|
||||
(Get-Python3Version),
|
||||
(Get-RubyVersion),
|
||||
(Get-SwiftVersion),
|
||||
(Get-JuliaVersion),
|
||||
(Get-KotlinVersion),
|
||||
(Get-ClangVersions),
|
||||
(Get-ClangFormatVersions)
|
||||
)
|
||||
|
||||
$markdown += New-MDList -Style Unordered -Lines ($runtimesList | Sort-Object)
|
||||
|
||||
$markdown += New-MDHeader "Package Management" -Level 3
|
||||
|
||||
$packageManagementList = @(
|
||||
(Get-HomebrewVersion),
|
||||
(Get-CpanVersion),
|
||||
(Get-GemVersion),
|
||||
(Get-MinicondaVersion),
|
||||
(Get-HelmVersion),
|
||||
(Get-NpmVersion),
|
||||
(Get-YarnVersion),
|
||||
(Get-PipxVersion),
|
||||
(Get-PipVersion),
|
||||
(Get-Pip3Version),
|
||||
(Get-VcpkgVersion)
|
||||
)
|
||||
|
||||
$markdown += New-MDList -Style Unordered -Lines ($packageManagementList | Sort-Object)
|
||||
$markdown += New-MDHeader "Environment variables" -Level 4
|
||||
$markdown += Build-PackageManagementEnvironmentTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
|
||||
$markdown += New-MDHeader "Project Management" -Level 3
|
||||
$projectManagementList = @(
|
||||
(Get-AntVersion),
|
||||
(Get-GradleVersion),
|
||||
(Get-MavenVersion),
|
||||
(Get-SbtVersion)
|
||||
)
|
||||
$installedSoftware = $softwareReport.Root.AddHeader("Installed Software")
|
||||
|
||||
# Language and Runtime
|
||||
$languageAndRuntime = $installedSoftware.AddHeader("Language and Runtime")
|
||||
$languageAndRuntime.AddToolVersion("Bash", $(Get-BashVersion))
|
||||
$languageAndRuntime.AddToolVersionsListInline("Clang", $(Get-ClangToolVersions -ToolName "clang"), "^\d+")
|
||||
$languageAndRuntime.AddToolVersionsListInline("Clang-format", $(Get-ClangToolVersions -ToolName "clang-format"), "^\d+")
|
||||
$languageAndRuntime.AddToolVersionsListInline("Clang-tidy", $(Get-ClangTidyVersions), "^\d+")
|
||||
$languageAndRuntime.AddToolVersion("Dash", $(Get-DashVersion))
|
||||
if (Test-IsUbuntu20) {
|
||||
$projectManagementList += @(
|
||||
(Get-LernaVersion)
|
||||
)
|
||||
$languageAndRuntime.AddToolVersion("Erlang", $(Get-ErlangVersion))
|
||||
$languageAndRuntime.AddToolVersion("Erlang rebar3", $(Get-ErlangRebar3Version))
|
||||
}
|
||||
$markdown += New-MDList -Style Unordered -Lines ($projectManagementList | Sort-Object)
|
||||
$languageAndRuntime.AddToolVersionsListInline("GNU C++", $(Get-CPPVersions), "^\d+")
|
||||
$languageAndRuntime.AddToolVersionsListInline("GNU Fortran", $(Get-FortranVersions), "^\d+")
|
||||
$languageAndRuntime.AddToolVersion("Julia", $(Get-JuliaVersion))
|
||||
$languageAndRuntime.AddToolVersion("Kotlin", $(Get-KotlinVersion))
|
||||
$languageAndRuntime.AddToolVersion("Mono", $(Get-MonoVersion))
|
||||
$languageAndRuntime.AddToolVersion("MSBuild", $(Get-MsbuildVersion))
|
||||
$languageAndRuntime.AddToolVersion("Node.js", $(Get-NodeVersion))
|
||||
$languageAndRuntime.AddToolVersion("Perl", $(Get-PerlVersion))
|
||||
$languageAndRuntime.AddToolVersion("Python", $(Get-PythonVersion))
|
||||
$languageAndRuntime.AddToolVersion("Python3", $(Get-Python3Version))
|
||||
$languageAndRuntime.AddToolVersion("Ruby", $(Get-RubyVersion))
|
||||
$languageAndRuntime.AddToolVersion("Swift", $(Get-SwiftVersion))
|
||||
|
||||
$markdown += New-MDHeader "Tools" -Level 3
|
||||
$toolsList = @(
|
||||
(Get-AnsibleVersion),
|
||||
(Get-AptFastVersion),
|
||||
(Get-AzCopyVersion),
|
||||
(Get-BazelVersion),
|
||||
(Get-BazeliskVersion),
|
||||
(Get-BicepVersion),
|
||||
(Get-BuildahVersion),
|
||||
(Get-CodeQLBundleVersion),
|
||||
(Get-CMakeVersion),
|
||||
(Get-DockerMobyClientVersion),
|
||||
(Get-DockerMobyServerVersion),
|
||||
(Get-DockerComposeV1Version),
|
||||
(Get-DockerComposeV2Version),
|
||||
(Get-DockerBuildxVersion),
|
||||
(Get-GitVersion),
|
||||
(Get-GitLFSVersion),
|
||||
(Get-GitFTPVersion),
|
||||
(Get-HavegedVersion),
|
||||
(Get-HerokuVersion),
|
||||
(Get-HHVMVersion),
|
||||
(Get-SVNVersion),
|
||||
(Get-JqVersion),
|
||||
(Get-YqVersion),
|
||||
(Get-KindVersion),
|
||||
(Get-KubectlVersion),
|
||||
(Get-KustomizeVersion),
|
||||
(Get-LeiningenVersion),
|
||||
(Get-MediainfoVersion),
|
||||
(Get-HGVersion),
|
||||
(Get-MinikubeVersion),
|
||||
(Get-NewmanVersion),
|
||||
(Get-NVersion),
|
||||
(Get-NvmVersion),
|
||||
(Get-OpensslVersion),
|
||||
(Get-PackerVersion),
|
||||
(Get-ParcelVersion),
|
||||
(Get-PhantomJSVersion),
|
||||
(Get-PodManVersion),
|
||||
(Get-PulumiVersion),
|
||||
(Get-RVersion),
|
||||
(Get-SkopeoVersion),
|
||||
(Get-SphinxVersion),
|
||||
(Get-TerraformVersion),
|
||||
(Get-YamllintVersion),
|
||||
(Get-ZstdVersion)
|
||||
)
|
||||
# Package Management
|
||||
$packageManagement = $installedSoftware.AddHeader("Package Management")
|
||||
$packageManagement.AddToolVersion("cpan", $(Get-CpanVersion))
|
||||
$packageManagement.AddToolVersion("Helm", $(Get-HelmVersion))
|
||||
$packageManagement.AddToolVersion("Homebrew", $(Get-HomebrewVersion))
|
||||
$packageManagement.AddToolVersion("Miniconda", $(Get-MinicondaVersion))
|
||||
$packageManagement.AddToolVersion("Npm", $(Get-NpmVersion))
|
||||
$packageManagement.AddToolVersion("NuGet", $(Get-NuGetVersion))
|
||||
$packageManagement.AddToolVersion("Pip", $(Get-PipVersion))
|
||||
$packageManagement.AddToolVersion("Pip3", $(Get-Pip3Version))
|
||||
$packageManagement.AddToolVersion("Pipx", $(Get-PipxVersion))
|
||||
$packageManagement.AddToolVersion("RubyGems", $(Get-GemVersion))
|
||||
$packageManagement.AddToolVersion("Vcpkg", $(Get-VcpkgVersion))
|
||||
$packageManagement.AddToolVersion("Yarn", $(Get-YarnVersion))
|
||||
$packageManagement.AddHeader("Environment variables").AddTable($(Build-PackageManagementEnvironmentTable))
|
||||
$packageManagement.AddHeader("Homebrew note").AddNote(@'
|
||||
Location: /home/linuxbrew
|
||||
Note: Homebrew is pre-installed on image but not added to PATH.
|
||||
run the eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" command
|
||||
to accomplish this.
|
||||
'@)
|
||||
|
||||
# Project Management
|
||||
$projectManagement = $installedSoftware.AddHeader("Project Management")
|
||||
if (Test-IsUbuntu20) {
|
||||
$toolsList += (Get-FastlaneVersion)
|
||||
$projectManagement.AddToolVersion("Ant", $(Get-AntVersion))
|
||||
$projectManagement.AddToolVersion("Gradle", $(Get-GradleVersion))
|
||||
}
|
||||
if ((Test-IsUbuntu20) -or (Test-IsUbuntu22)) {
|
||||
$projectManagement.AddToolVersion("Lerna", $(Get-LernaVersion))
|
||||
}
|
||||
$projectManagement.AddToolVersion("Maven", $(Get-MavenVersion))
|
||||
if (Test-IsUbuntu20) {
|
||||
$projectManagement.AddToolVersion("Sbt", $(Get-SbtVersion))
|
||||
}
|
||||
|
||||
$markdown += New-MDList -Style Unordered -Lines ($toolsList | Sort-Object)
|
||||
|
||||
$markdown += New-MDHeader "CLI Tools" -Level 3
|
||||
$markdown += New-MDList -Style Unordered -Lines (@(
|
||||
(Get-AlibabaCloudCliVersion),
|
||||
(Get-AWSCliVersion),
|
||||
(Get-AWSCliSessionManagerPluginVersion),
|
||||
(Get-AWSSAMVersion),
|
||||
(Get-AzureCliVersion),
|
||||
(Get-AzureDevopsVersion),
|
||||
(Get-GitHubCliVersion),
|
||||
(Get-GoogleCloudSDKVersion),
|
||||
(Get-HubCliVersion),
|
||||
(Get-NetlifyCliVersion),
|
||||
(Get-OCCliVersion),
|
||||
(Get-ORASCliVersion),
|
||||
(Get-VerselCliversion)
|
||||
) | Sort-Object
|
||||
)
|
||||
|
||||
$markdown += New-MDHeader "Java" -Level 3
|
||||
$markdown += Get-JavaVersions | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
|
||||
if (Test-IsUbuntu20) {
|
||||
$markdown += New-MDHeader "GraalVM" -Level 3
|
||||
$markdown += Build-GraalVMTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
# Tools
|
||||
$tools = $installedSoftware.AddHeader("Tools")
|
||||
$tools.AddToolVersion("Ansible", $(Get-AnsibleVersion))
|
||||
$tools.AddToolVersion("apt-fast", $(Get-AptFastVersion))
|
||||
$tools.AddToolVersion("AzCopy", $(Get-AzCopyVersion))
|
||||
$tools.AddToolVersion("Bazel", $(Get-BazelVersion))
|
||||
$tools.AddToolVersion("Bazelisk", $(Get-BazeliskVersion))
|
||||
$tools.AddToolVersion("Bicep", $(Get-BicepVersion))
|
||||
$tools.AddToolVersion("Buildah", $(Get-BuildahVersion))
|
||||
$tools.AddToolVersion("CMake", $(Get-CMakeVersion))
|
||||
$tools.AddToolVersion("CodeQL Action Bundles", $(Get-CodeQLBundleVersions))
|
||||
$tools.AddToolVersion("Docker Amazon ECR Credential Helper", $(Get-DockerAmazonECRCredHelperVersion))
|
||||
$tools.AddToolVersion("Docker Compose v1", $(Get-DockerComposeV1Version))
|
||||
$tools.AddToolVersion("Docker Compose v2", $(Get-DockerComposeV2Version))
|
||||
$tools.AddToolVersion("Docker-Buildx", $(Get-DockerBuildxVersion))
|
||||
$tools.AddToolVersion("Docker-Moby Client", $(Get-DockerMobyClientVersion))
|
||||
$tools.AddToolVersion("Docker-Moby Server", $(Get-DockerMobyServerVersion))
|
||||
if ((Test-IsUbuntu20) -or (Test-IsUbuntu22)) {
|
||||
$tools.AddToolVersion("Fastlane", $(Get-FastlaneVersion))
|
||||
}
|
||||
$tools.AddToolVersion("Git", $(Get-GitVersion))
|
||||
$tools.AddToolVersion("Git LFS", $(Get-GitLFSVersion))
|
||||
$tools.AddToolVersion("Git-ftp", $(Get-GitFTPVersion))
|
||||
$tools.AddToolVersion("Haveged", $(Get-HavegedVersion))
|
||||
$tools.AddToolVersion("Heroku", $(Get-HerokuVersion))
|
||||
if (Test-IsUbuntu20) {
|
||||
$tools.AddToolVersion("HHVM (HipHop VM)", $(Get-HHVMVersion))
|
||||
}
|
||||
$tools.AddToolVersion("jq", $(Get-JqVersion))
|
||||
$tools.AddToolVersion("Kind", $(Get-KindVersion))
|
||||
$tools.AddToolVersion("Kubectl", $(Get-KubectlVersion))
|
||||
$tools.AddToolVersion("Kustomize", $(Get-KustomizeVersion))
|
||||
$tools.AddToolVersion("Leiningen", $(Get-LeiningenVersion))
|
||||
$tools.AddToolVersion("MediaInfo", $(Get-MediainfoVersion))
|
||||
$tools.AddToolVersion("Mercurial", $(Get-HGVersion))
|
||||
$tools.AddToolVersion("Minikube", $(Get-MinikubeVersion))
|
||||
$tools.AddToolVersion("n", $(Get-NVersion))
|
||||
$tools.AddToolVersion("Newman", $(Get-NewmanVersion))
|
||||
$tools.AddToolVersion("nvm", $(Get-NvmVersion))
|
||||
$tools.AddToolVersion("OpenSSL", $(Get-OpensslVersion))
|
||||
$tools.AddToolVersion("Packer", $(Get-PackerVersion))
|
||||
$tools.AddToolVersion("Parcel", $(Get-ParcelVersion))
|
||||
if (Test-IsUbuntu20) {
|
||||
$tools.AddToolVersion("PhantomJS", $(Get-PhantomJSVersion))
|
||||
}
|
||||
$tools.AddToolVersion("Podman", $(Get-PodManVersion))
|
||||
$tools.AddToolVersion("Pulumi", $(Get-PulumiVersion))
|
||||
$tools.AddToolVersion("R", $(Get-RVersion))
|
||||
$tools.AddToolVersion("Skopeo", $(Get-SkopeoVersion))
|
||||
$tools.AddToolVersion("Sphinx Open Source Search Server", $(Get-SphinxVersion))
|
||||
$tools.AddToolVersion("SVN", $(Get-SVNVersion))
|
||||
$tools.AddToolVersion("Terraform", $(Get-TerraformVersion))
|
||||
$tools.AddToolVersion("yamllint", $(Get-YamllintVersion))
|
||||
$tools.AddToolVersion("yq", $(Get-YqVersion))
|
||||
$tools.AddToolVersion("zstd", $(Get-ZstdVersion))
|
||||
|
||||
$markdown += Build-PHPSection
|
||||
# CLI Tools
|
||||
$cliTools = $installedSoftware.AddHeader("CLI Tools")
|
||||
$cliTools.AddToolVersion("Alibaba Cloud CLI", $(Get-AlibabaCloudCliVersion))
|
||||
$cliTools.AddToolVersion("AWS CLI", $(Get-AWSCliVersion))
|
||||
$cliTools.AddToolVersion("AWS CLI Session Manager Plugin", $(Get-AWSCliSessionManagerPluginVersion))
|
||||
$cliTools.AddToolVersion("AWS SAM CLI", $(Get-AWSSAMVersion))
|
||||
$cliTools.AddToolVersion("Azure CLI", $(Get-AzureCliVersion))
|
||||
$cliTools.AddToolVersion("Azure CLI (azure-devops)", $(Get-AzureDevopsVersion))
|
||||
$cliTools.AddToolVersion("GitHub CLI", $(Get-GitHubCliVersion))
|
||||
$cliTools.AddToolVersion("Google Cloud SDK", $(Get-GoogleCloudSDKVersion))
|
||||
$cliTools.AddToolVersion("Hub CLI", $(Get-HubCliVersion))
|
||||
$cliTools.AddToolVersion("Netlify CLI", $(Get-NetlifyCliVersion))
|
||||
$cliTools.AddToolVersion("OpenShift CLI", $(Get-OCCliVersion))
|
||||
$cliTools.AddToolVersion("ORAS CLI", $(Get-ORASCliVersion))
|
||||
$cliTools.AddToolVersion("Vercel CLI", $(Get-VerselCliversion))
|
||||
|
||||
$markdown += New-MDHeader "Haskell" -Level 3
|
||||
$markdown += New-MDList -Style Unordered -Lines (@(
|
||||
(Get-GHCVersion),
|
||||
(Get-GHCupVersion),
|
||||
(Get-CabalVersion),
|
||||
(Get-StackVersion)
|
||||
) | Sort-Object
|
||||
)
|
||||
|
||||
$markdown += New-MDHeader "Rust Tools" -Level 3
|
||||
$markdown += New-MDList -Style Unordered -Lines (@(
|
||||
(Get-RustVersion),
|
||||
(Get-RustupVersion),
|
||||
(Get-RustdocVersion),
|
||||
(Get-CargoVersion)
|
||||
) | Sort-Object
|
||||
)
|
||||
$installedSoftware.AddHeader("Java").AddTable($(Get-JavaVersionsTable))
|
||||
|
||||
$markdown += New-MDHeader "Packages" -Level 4
|
||||
$markdown += New-MDList -Style Unordered -Lines (@(
|
||||
(Get-BindgenVersion),
|
||||
(Get-CargoAuditVersion),
|
||||
(Get-CargoOutdatedVersion),
|
||||
(Get-CargoClippyVersion),
|
||||
(Get-CbindgenVersion),
|
||||
(Get-RustfmtVersion)
|
||||
) | Sort-Object
|
||||
)
|
||||
$phpTools = $installedSoftware.AddHeader("PHP Tools")
|
||||
$phpTools.AddToolVersionsListInline("PHP", $(Get-PHPVersions), "^\d+\.\d+")
|
||||
$phpTools.AddToolVersion("Composer", $(Get-ComposerVersion))
|
||||
$phpTools.AddToolVersion("PHPUnit", $(Get-PHPUnitVersion))
|
||||
$phpTools.AddNote("Both Xdebug and PCOV extensions are installed, but only Xdebug is enabled.")
|
||||
|
||||
$markdown += New-MDHeader "Browsers and Drivers" -Level 3
|
||||
$haskellTools = $installedSoftware.AddHeader("Haskell Tools")
|
||||
$haskellTools.AddToolVersion("Cabal", $(Get-CabalVersion))
|
||||
$haskellTools.AddToolVersion("GHC", $(Get-GHCVersion))
|
||||
$haskellTools.AddToolVersion("GHCup", $(Get-GHCupVersion))
|
||||
$haskellTools.AddToolVersion("Stack", $(Get-StackVersion))
|
||||
|
||||
$browsersAndDriversList = @(
|
||||
(Get-ChromeVersion),
|
||||
(Get-ChromeDriverVersion),
|
||||
(Get-FirefoxVersion),
|
||||
(Get-GeckodriverVersion),
|
||||
(Get-ChromiumVersion),
|
||||
(Get-SeleniumVersion)
|
||||
)
|
||||
Initialize-RustEnvironment
|
||||
$rustTools = $installedSoftware.AddHeader("Rust Tools")
|
||||
$rustTools.AddToolVersion("Cargo", $(Get-CargoVersion))
|
||||
$rustTools.AddToolVersion("Rust", $(Get-RustVersion))
|
||||
$rustTools.AddToolVersion("Rustdoc", $(Get-RustdocVersion))
|
||||
$rustTools.AddToolVersion("Rustup", $(Get-RustupVersion))
|
||||
$rustToolsPackages = $rustTools.AddHeader("Packages")
|
||||
$rustToolsPackages.AddToolVersion("Bindgen", $(Get-BindgenVersion))
|
||||
$rustToolsPackages.AddToolVersion("Cargo audit", $(Get-CargoAuditVersion))
|
||||
$rustToolsPackages.AddToolVersion("Cargo clippy", $(Get-CargoClippyVersion))
|
||||
$rustToolsPackages.AddToolVersion("Cargo outdated", $(Get-CargoOutdatedVersion))
|
||||
$rustToolsPackages.AddToolVersion("Cbindgen", $(Get-CbindgenVersion))
|
||||
$rustToolsPackages.AddToolVersion("Rustfmt", $(Get-RustfmtVersion))
|
||||
|
||||
$markdown += New-MDList -Style Unordered -Lines $browsersAndDriversList
|
||||
$markdown += New-MDHeader "Environment variables" -Level 4
|
||||
$markdown += Build-BrowserWebdriversEnvironmentTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
$browsersTools = $installedSoftware.AddHeader("Browsers and Drivers")
|
||||
$browsersTools.AddToolVersion("Google Chrome", $(Get-ChromeVersion))
|
||||
$browsersTools.AddToolVersion("ChromeDriver", $(Get-ChromeDriverVersion))
|
||||
$browsersTools.AddToolVersion("Chromium", $(Get-ChromiumVersion))
|
||||
$browsersTools.AddToolVersion("Microsoft Edge", $(Get-EdgeVersion))
|
||||
$browsersTools.AddToolVersion("Microsoft Edge WebDriver", $(Get-EdgeDriverVersion))
|
||||
$browsersTools.AddToolVersion("Selenium server", $(Get-SeleniumVersion))
|
||||
$browsersTools.AddToolVersion("Mozilla Firefox", $(Get-FirefoxVersion))
|
||||
$browsersTools.AddToolVersion("Geckodriver", $(Get-GeckodriverVersion))
|
||||
$browsersTools.AddHeader("Environment variables").AddTable($(Build-BrowserWebdriversEnvironmentTable))
|
||||
|
||||
$markdown += New-MDHeader ".NET Core SDK" -Level 3
|
||||
$markdown += New-MDList -Style Unordered -Lines @(
|
||||
(Get-DotNetCoreSdkVersions)
|
||||
)
|
||||
$netCoreTools = $installedSoftware.AddHeader(".NET Tools")
|
||||
$netCoreTools.AddToolVersionsListInline(".NET Core SDK", $(Get-DotNetCoreSdkVersions), "^\d+\.\d+\.\d")
|
||||
$netCoreTools.AddNodes($(Get-DotnetTools))
|
||||
|
||||
$markdown += New-MDHeader ".NET tools" -Level 3
|
||||
$tools = Get-DotnetTools
|
||||
$markdown += New-MDList -Lines $tools -Style Unordered
|
||||
$databasesTools = $installedSoftware.AddHeader("Databases")
|
||||
if (Test-IsUbuntu20) {
|
||||
$databasesTools.AddToolVersion("MongoDB", $(Get-MongoDbVersion))
|
||||
}
|
||||
$databasesTools.AddToolVersion("sqlite3", $(Get-SqliteVersion))
|
||||
$databasesTools.AddNode($(Build-PostgreSqlSection))
|
||||
$databasesTools.AddNode($(Build-MySQLSection))
|
||||
$databasesTools.AddNode($(Build-MSSQLToolsSection))
|
||||
|
||||
$markdown += New-MDHeader "Databases" -Level 3
|
||||
$markdown += New-MDList -Style Unordered -Lines (@(
|
||||
(Get-PostgreSqlVersion),
|
||||
(Get-MongoDbVersion),
|
||||
(Get-SqliteVersion)
|
||||
) | Sort-Object
|
||||
)
|
||||
$cachedTools = $installedSoftware.AddHeader("Cached Tools")
|
||||
$cachedTools.AddToolVersionsList("Go", $(Get-ToolcacheGoVersions), "^\d+\.\d+")
|
||||
$cachedTools.AddToolVersionsList("Node.js", $(Get-ToolcacheNodeVersions), "^\d+")
|
||||
$cachedTools.AddToolVersionsList("Python", $(Get-ToolcachePythonVersions), "^\d+\.\d+")
|
||||
$cachedTools.AddToolVersionsList("PyPy", $(Get-ToolcachePyPyVersions), "^\d+\.\d+")
|
||||
$cachedTools.AddToolVersionsList("Ruby", $(Get-ToolcacheRubyVersions), "^\d+\.\d+")
|
||||
|
||||
$markdown += Build-MySQLSection
|
||||
$markdown += Build-MSSQLToolsSection
|
||||
$powerShellTools = $installedSoftware.AddHeader("PowerShell Tools")
|
||||
$powerShellTools.AddToolVersion("PowerShell", $(Get-PowershellVersion))
|
||||
$powerShellTools.AddHeader("PowerShell Modules").AddNodes($(Get-PowerShellModules))
|
||||
|
||||
$markdown += New-MDHeader "Cached Tools" -Level 3
|
||||
$markdown += Build-CachedToolsSection
|
||||
$installedSoftware.AddHeader("Web Servers").AddTable($(Build-WebServersTable))
|
||||
|
||||
$markdown += New-MDHeader "Environment variables" -Level 4
|
||||
$markdown += Build-GoEnvironmentTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
$androidTools = $installedSoftware.AddHeader("Android")
|
||||
$androidTools.AddTable($(Build-AndroidTable))
|
||||
$androidTools.AddHeader("Environment variables").AddTable($(Build-AndroidEnvironmentTable))
|
||||
|
||||
$markdown += New-MDHeader "PowerShell Tools" -Level 3
|
||||
$markdown += New-MDList -Lines (Get-PowershellVersion) -Style Unordered
|
||||
$installedSoftware.AddHeader("Cached Docker images").AddTable($(Get-CachedDockerImagesTableData))
|
||||
$installedSoftware.AddHeader("Installed apt packages").AddTable($(Get-AptPackages))
|
||||
|
||||
$markdown += New-MDHeader "PowerShell Modules" -Level 4
|
||||
$markdown += Get-PowerShellModules | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
$markdown += New-MDHeader "Az PowerShell Modules" -Level 4
|
||||
$markdown += New-MDList -Style Unordered -Lines @(
|
||||
(Get-AzModuleVersions)
|
||||
)
|
||||
|
||||
$markdown += Build-WebServersSection
|
||||
|
||||
$markdown += New-MDHeader "Android" -Level 3
|
||||
$markdown += Build-AndroidTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
$markdown += New-MDHeader "Environment variables" -Level 4
|
||||
$markdown += Build-AndroidEnvironmentTable | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
|
||||
$markdown += New-MDHeader "Cached Docker images" -Level 3
|
||||
$markdown += Get-CachedDockerImagesTableData | New-MDTable
|
||||
$markdown += New-MDNewLine
|
||||
|
||||
$markdown += New-MDHeader "Installed apt packages" -Level 3
|
||||
$markdown += Get-AptPackages | New-MDTable
|
||||
|
||||
Test-BlankElement
|
||||
$markdown | Out-File -FilePath "${OutputDirectory}/Ubuntu-Readme.md"
|
||||
$softwareReport.ToJson() | Out-File -FilePath "${OutputDirectory}/software-report.json" -Encoding UTF8NoBOM
|
||||
$softwareReport.ToMarkdown() | Out-File -FilePath "${OutputDirectory}/software-report.md" -Encoding UTF8NoBOM
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function Get-JavaVersions {
|
||||
function Get-JavaVersionsTable {
|
||||
$javaToolcacheVersions = Get-ChildItem $env:AGENT_TOOLSDIRECTORY/Java*/* -Directory | Sort-Object { [int]$_.Name.Split(".")[0] }
|
||||
|
||||
$existingVersions = $javaToolcacheVersions | ForEach-Object {
|
||||
|
||||
@@ -5,52 +5,51 @@ function Initialize-RustEnvironment {
|
||||
}
|
||||
|
||||
function Get-RustVersion {
|
||||
Initialize-RustEnvironment
|
||||
$rustVersion = $(rustc --version) | Take-OutputPart -Part 1
|
||||
return "Rust $rustVersion"
|
||||
return $rustVersion
|
||||
}
|
||||
|
||||
function Get-BindgenVersion {
|
||||
$bindgenVersion = $(bindgen --version) | Take-OutputPart -Part 1
|
||||
return "Bindgen $bindgenVersion"
|
||||
return $bindgenVersion
|
||||
}
|
||||
|
||||
function Get-CargoVersion {
|
||||
$cargoVersion = $(cargo --version) | Take-OutputPart -Part 1
|
||||
return "Cargo $cargoVersion"
|
||||
return $cargoVersion
|
||||
}
|
||||
|
||||
function Get-CargoAuditVersion {
|
||||
$cargoAuditVersion = $(cargo audit --version) | Take-OutputPart -Part 1
|
||||
return "Cargo audit $cargoAuditVersion"
|
||||
$cargoAuditVersion = $(cargo-audit --version) | Take-OutputPart -Part 1
|
||||
return $cargoAuditVersion
|
||||
}
|
||||
|
||||
function Get-CargoOutdatedVersion {
|
||||
$cargoOutdatedVersion = $(cargo outdated --version) | Take-OutputPart -Part 1 -Delimiter "v"
|
||||
return "Cargo outdated $cargoOutdatedVersion"
|
||||
$cargoOutdatedVersion = cargo outdated --version | Take-OutputPart -Part 1
|
||||
return $cargoOutdatedVersion
|
||||
}
|
||||
|
||||
function Get-CargoClippyVersion {
|
||||
$cargoClippyVersion = $(cargo-clippy --version) | Take-OutputPart -Part 1
|
||||
return "Cargo clippy $cargoClippyVersion"
|
||||
return $cargoClippyVersion
|
||||
}
|
||||
|
||||
function Get-CbindgenVersion {
|
||||
$cbindgenVersion = $(cbindgen --version) | Take-OutputPart -Part 1
|
||||
return "Cbindgen $cbindgenVersion"
|
||||
return $cbindgenVersion
|
||||
}
|
||||
|
||||
function Get-RustupVersion {
|
||||
$rustupVersion = $(rustup --version) | Take-OutputPart -Part 1
|
||||
return "Rustup $rustupVersion"
|
||||
return $rustupVersion
|
||||
}
|
||||
|
||||
function Get-RustdocVersion {
|
||||
$rustdocVersion = $(rustdoc --version) | Take-OutputPart -Part 1
|
||||
return "Rustdoc $rustdocVersion"
|
||||
return $rustdocVersion
|
||||
}
|
||||
|
||||
function Get-RustfmtVersion {
|
||||
$rustfmtVersion = $(rustfmt --version) | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "-"
|
||||
return "Rustfmt $rustfmtVersion"
|
||||
return $rustfmtVersion
|
||||
}
|
||||
|
||||
@@ -1,295 +1,294 @@
|
||||
function Get-AnsibleVersion {
|
||||
$ansibleVersion = (ansible --version)[0] -replace "[^\d.]"
|
||||
return "Ansible $ansibleVersion"
|
||||
return $ansibleVersion
|
||||
}
|
||||
|
||||
function Get-AptFastVersion {
|
||||
$versionFileContent = Get-Content (which apt-fast) -Raw
|
||||
$match = [Regex]::Match($versionFileContent, '# apt-fast v(.+)\n')
|
||||
$aptFastVersion = $match.Groups[1].Value
|
||||
return "apt-fast $aptFastVersion"
|
||||
return $match.Groups[1].Value
|
||||
}
|
||||
|
||||
function Get-AzCopyVersion {
|
||||
$azcopyVersion = azcopy --version | Take-OutputPart -Part 2
|
||||
return "AzCopy $azcopyVersion (available by ``azcopy`` and ``azcopy10`` aliases)"
|
||||
return "$azcopyVersion - available by ``azcopy`` and ``azcopy10`` aliases"
|
||||
}
|
||||
|
||||
function Get-BazelVersion {
|
||||
$bazelVersion = bazel --version | Select-String "bazel" | Take-OutputPart -Part 1
|
||||
return "Bazel $bazelVersion"
|
||||
return $bazelVersion
|
||||
}
|
||||
|
||||
function Get-BazeliskVersion {
|
||||
$result = Get-CommandResult "bazelisk version" -Multiline
|
||||
$bazeliskVersion = $result.Output | Select-String "Bazelisk version:" | Take-OutputPart -Part 2 | Take-OutputPart -Part 0 -Delimiter "v"
|
||||
return "Bazelisk $bazeliskVersion"
|
||||
return $bazeliskVersion
|
||||
}
|
||||
|
||||
function Get-BicepVersion {
|
||||
(bicep --version | Out-String) -match "bicep cli version (?<version>\d+\.\d+\.\d+)" | Out-Null
|
||||
$bicepVersion = $Matches.Version
|
||||
return "Bicep $bicepVersion"
|
||||
return $Matches.Version
|
||||
}
|
||||
|
||||
function Get-CodeQLBundleVersion {
|
||||
function Get-CodeQLBundleVersions {
|
||||
$CodeQLVersionsWildcard = Join-Path $Env:AGENT_TOOLSDIRECTORY -ChildPath "CodeQL" | Join-Path -ChildPath "*"
|
||||
$CodeQLVersionPath = Get-ChildItem $CodeQLVersionsWildcard | Select-Object -First 1 -Expand FullName
|
||||
$CodeQLPath = Join-Path $CodeQLVersionPath -ChildPath "x64" | Join-Path -ChildPath "codeql" | Join-Path -ChildPath "codeql"
|
||||
$CodeQLVersion = & $CodeQLPath version --quiet
|
||||
return "CodeQL Action Bundle $CodeQLVersion"
|
||||
$CodeQLVersionPaths = Get-ChildItem $CodeQLVersionsWildcard
|
||||
$CodeQlVersions=@()
|
||||
foreach ($CodeQLVersionPath in $CodeQLVersionPaths) {
|
||||
$FullCodeQLVersionPath = $CodeQLVersionPath | Select-Object -Expand FullName
|
||||
$CodeQLPath = Join-Path $FullCodeQLVersionPath -ChildPath "x64" | Join-Path -ChildPath "codeql" | Join-Path -ChildPath "codeql"
|
||||
$CodeQLVersion = & $CodeQLPath version --quiet
|
||||
$CodeQLVersions += $CodeQLVersion
|
||||
}
|
||||
return $CodeQLVersions
|
||||
}
|
||||
|
||||
function Get-PodManVersion {
|
||||
$podmanVersion = podman --version | Take-OutputPart -Part 2
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "containers"
|
||||
return "Podman $podmanVersion (apt source repository: $aptSourceRepo)"
|
||||
return $podmanVersion
|
||||
}
|
||||
|
||||
function Get-BuildahVersion {
|
||||
$buildahVersion = buildah --version | Take-OutputPart -Part 2
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "containers"
|
||||
return "Buildah $buildahVersion (apt source repository: $aptSourceRepo)"
|
||||
return $buildahVersion
|
||||
}
|
||||
|
||||
function Get-SkopeoVersion {
|
||||
$skopeoVersion = skopeo --version | Take-OutputPart -Part 2
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "containers"
|
||||
return "Skopeo $skopeoVersion (apt source repository: $aptSourceRepo)"
|
||||
return $skopeoVersion
|
||||
}
|
||||
|
||||
function Get-CMakeVersion {
|
||||
$cmakeVersion = cmake --version | Select-Object -First 1 | Take-OutputPart -Part 2
|
||||
return "CMake $cmakeVersion"
|
||||
return $cmakeVersion
|
||||
}
|
||||
|
||||
function Get-DockerComposeV1Version {
|
||||
$composeVersion = docker-compose -v | Take-OutputPart -Part 2 | Take-OutputPart -Part 0 -Delimiter ","
|
||||
return "Docker Compose v1 $composeVersion"
|
||||
return $composeVersion
|
||||
}
|
||||
|
||||
function Get-DockerComposeV2Version {
|
||||
$composeVersion = docker compose version | Take-OutputPart -Part 3
|
||||
return "Docker Compose v2 $composeVersion"
|
||||
return $composeVersion
|
||||
}
|
||||
|
||||
function Get-DockerMobyClientVersion {
|
||||
$dockerClientVersion = sudo docker version --format '{{.Client.Version}}'
|
||||
return "Docker-Moby Client $dockerClientVersion"
|
||||
return $dockerClientVersion
|
||||
}
|
||||
|
||||
function Get-DockerMobyServerVersion {
|
||||
$dockerServerVersion = sudo docker version --format '{{.Server.Version}}'
|
||||
return "Docker-Moby Server $dockerServerVersion"
|
||||
return $dockerServerVersion
|
||||
}
|
||||
|
||||
function Get-DockerBuildxVersion {
|
||||
$buildxVersion = docker buildx version | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "+"
|
||||
return "Docker-Buildx $buildxVersion"
|
||||
return $buildxVersion
|
||||
}
|
||||
|
||||
function Get-DockerAmazonECRCredHelperVersion {
|
||||
$ecrVersion = docker-credential-ecr-login -v | Select-String "Version:" | Take-OutputPart -Part 1
|
||||
return $ecrVersion
|
||||
}
|
||||
|
||||
function Get-GitVersion {
|
||||
$result = Get-CommandResult "git --version"
|
||||
$gitVersion = $result.Output | Take-OutputPart -Part 2
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "git-core"
|
||||
return "Git $gitVersion (apt source repository: $aptSourceRepo)"
|
||||
$gitVersion = git --version | Take-OutputPart -Part -1
|
||||
return $gitVersion
|
||||
}
|
||||
|
||||
function Get-GitLFSVersion {
|
||||
$result = Get-CommandResult "git-lfs --version"
|
||||
$gitlfsversion = $result.Output | Take-OutputPart -Part 0 | Take-OutputPart -Part 1 -Delimiter "/"
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "git-lfs"
|
||||
return "Git LFS $gitlfsversion (apt source repository: $aptSourceRepo)"
|
||||
return $gitlfsversion
|
||||
}
|
||||
|
||||
function Get-GitFTPVersion {
|
||||
$gitftpVersion = git-ftp --version | Take-OutputPart -Part 2
|
||||
return "Git-ftp $gitftpVersion"
|
||||
return $gitftpVersion
|
||||
}
|
||||
|
||||
function Get-GoogleCloudSDKVersion {
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "google-cloud-sdk"
|
||||
return "$(gcloud --version | Select-Object -First 1) (apt source repository: $aptSourceRepo)"
|
||||
return (gcloud --version | Select-Object -First 1) | Take-OutputPart -Part 3
|
||||
}
|
||||
|
||||
function Get-HavegedVersion {
|
||||
$havegedVersion = dpkg-query --showformat='${Version}' --show haveged | Take-OutputPart -Part 0 -Delimiter "-"
|
||||
return "Haveged $havegedVersion"
|
||||
return $havegedVersion
|
||||
}
|
||||
|
||||
function Get-HerokuVersion {
|
||||
$herokuVersion = heroku version | Take-OutputPart -Part 0 | Take-OutputPart -Part 1 -Delimiter "/"
|
||||
return "Heroku $herokuVersion"
|
||||
return $herokuVersion
|
||||
}
|
||||
|
||||
function Get-HHVMVersion {
|
||||
$hhvmVersion = hhvm --version | Select-Object -First 1 | Take-OutputPart -Part 2
|
||||
return "HHVM (HipHop VM) $hhvmVersion"
|
||||
return $hhvmVersion
|
||||
}
|
||||
|
||||
function Get-SVNVersion {
|
||||
$svnVersion = svn --version | Select-Object -First 1 | Take-OutputPart -Part 2
|
||||
return "SVN $svnVersion"
|
||||
return $svnVersion
|
||||
}
|
||||
|
||||
function Get-KustomizeVersion {
|
||||
$kustomizeVersion = kustomize version --short | Take-OutputPart -Part 0 | Take-OutputPart -Part 1 -Delimiter "v"
|
||||
return "Kustomize $kustomizeVersion"
|
||||
return $kustomizeVersion
|
||||
}
|
||||
|
||||
function Get-KindVersion {
|
||||
$kindVersion = kind version | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "v"
|
||||
return "Kind $kindVersion"
|
||||
return $kindVersion
|
||||
}
|
||||
|
||||
function Get-KubectlVersion {
|
||||
$kubectlVersion = kubectl version --client --short | Take-OutputPart -Part 2 | Take-OutputPart -Part 0 -Delimiter "v"
|
||||
return "Kubectl $kubectlVersion"
|
||||
$kubectlVersion = (kubectl version --client --output=json | ConvertFrom-Json).clientVersion.gitVersion.Replace('v','')
|
||||
return $kubectlVersion
|
||||
}
|
||||
|
||||
function Get-MinikubeVersion {
|
||||
$minikubeVersion = minikube version --short | Take-OutputPart -Part 0 -Delimiter "v"
|
||||
return "Minikube $minikubeVersion"
|
||||
return $minikubeVersion
|
||||
}
|
||||
|
||||
function Get-HGVersion {
|
||||
$hgVersion = hg --version | Select-Object -First 1 | Take-OutputPart -Part -1 | Take-OutputPart -Part 0 -Delimiter ")"
|
||||
return "Mercurial $hgVersion"
|
||||
return $hgVersion
|
||||
}
|
||||
|
||||
function Get-LeiningenVersion {
|
||||
return "$(lein -v | Take-OutputPart -Part 0,1)"
|
||||
return "$(lein -v | Take-OutputPart -Part 1)"
|
||||
}
|
||||
|
||||
function Get-MediainfoVersion {
|
||||
$mediainfoVersion = (mediainfo --version | Select-Object -Index 1 | Take-OutputPart -Part 2).Replace('v', '')
|
||||
return "MediaInfo $mediainfoVersion"
|
||||
return $mediainfoVersion
|
||||
}
|
||||
|
||||
function Get-NewmanVersion {
|
||||
return "Newman $(newman --version)"
|
||||
return $(newman --version)
|
||||
}
|
||||
|
||||
function Get-NVersion {
|
||||
$nVersion = (n --version).Replace('v', '')
|
||||
return "n $nVersion"
|
||||
return $nVersion
|
||||
}
|
||||
|
||||
function Get-NvmVersion {
|
||||
$nvmVersion = bash -c "source /etc/skel/.nvm/nvm.sh && nvm --version"
|
||||
return "nvm $nvmVersion"
|
||||
return $nvmVersion
|
||||
}
|
||||
|
||||
function Get-PackerVersion {
|
||||
# Packer 1.7.1 has a bug and outputs version to stderr instead of stdout https://github.com/hashicorp/packer/issues/10855
|
||||
$result = (Get-CommandResult "packer --version").Output
|
||||
$packerVersion = [regex]::matches($result, "(\d+.){2}\d+").Value
|
||||
return "Packer $packerVersion"
|
||||
$packerVersion = packer --version
|
||||
return $packerVersion
|
||||
}
|
||||
|
||||
function Get-PhantomJSVersion {
|
||||
return "PhantomJS $(phantomjs --version)"
|
||||
$env:OPENSSL_CONF="/etc/ssl"; phantomjs --version
|
||||
return $(phantomjs --version)
|
||||
}
|
||||
|
||||
function Get-TerraformVersion {
|
||||
return (terraform version | Select-String "^Terraform").Line.Replace('v','')
|
||||
return (terraform version | Select-String "^Terraform").Line.Replace('v','') | Take-OutputPart -Part 1
|
||||
}
|
||||
|
||||
function Get-JqVersion {
|
||||
$jqVersion = jq --version | Take-OutputPart -Part 1 -Delimiter "-"
|
||||
return "jq $jqVersion"
|
||||
return $jqVersion
|
||||
}
|
||||
|
||||
function Get-AzureCliVersion {
|
||||
$azcliVersion = (az version | ConvertFrom-Json).'azure-cli'
|
||||
$aptSourceRepo = Get-AptSourceRepository -PackageName "azure-cli"
|
||||
return "Azure CLI (azure-cli) $azcliVersion (installation method: $aptSourceRepo)"
|
||||
return $azcliVersion
|
||||
}
|
||||
|
||||
function Get-AzureDevopsVersion {
|
||||
$azdevopsVersion = (az version | ConvertFrom-Json).extensions.'azure-devops'
|
||||
return "Azure CLI (azure-devops) $azdevopsVersion"
|
||||
return $azdevopsVersion
|
||||
}
|
||||
|
||||
function Get-AlibabaCloudCliVersion {
|
||||
return "Alibaba Cloud CLI $(aliyun version)"
|
||||
return $(aliyun version)
|
||||
}
|
||||
|
||||
function Get-AWSCliVersion {
|
||||
$result = Get-CommandResult "aws --version"
|
||||
$awsVersion = $result.Output | Take-OutputPart -Part 0 | Take-OutputPart -Part 1 -Delimiter "/"
|
||||
return "AWS CLI $awsVersion"
|
||||
return $awsVersion
|
||||
}
|
||||
|
||||
function Get-AWSCliSessionManagerPluginVersion {
|
||||
$result = (Get-CommandResult "session-manager-plugin --version").Output
|
||||
return "AWS CLI Session manager plugin $result"
|
||||
return $result
|
||||
}
|
||||
|
||||
function Get-AWSSAMVersion {
|
||||
return "AWS SAM CLI $(sam --version | Take-OutputPart -Part -1)"
|
||||
return $(sam --version | Take-OutputPart -Part -1)
|
||||
}
|
||||
|
||||
function Get-FastlaneVersion {
|
||||
$fastlaneVersion = fastlane --version | Select-String "^fastlane [0-9]" | Take-OutputPart -Part 1
|
||||
return "Fastlane $fastlaneVersion"
|
||||
return $fastlaneVersion
|
||||
}
|
||||
|
||||
function Get-HubCliVersion {
|
||||
$hubVersion = hub --version | Select-String "hub version" | Take-OutputPart -Part 2
|
||||
return "Hub CLI $hubVersion"
|
||||
return $hubVersion
|
||||
}
|
||||
|
||||
function Get-GitHubCliVersion {
|
||||
$ghVersion = gh --version | Select-String "gh version" | Take-OutputPart -Part 2
|
||||
return "GitHub CLI $ghVersion"
|
||||
return $ghVersion
|
||||
}
|
||||
|
||||
function Get-NetlifyCliVersion {
|
||||
$netlifyVersion = netlify --version | Take-OutputPart -Part 0 | Take-OutputPart -Part 1 -Delimiter "/"
|
||||
return "Netlify CLI $netlifyVersion"
|
||||
return $netlifyVersion
|
||||
}
|
||||
|
||||
function Get-OCCliVersion {
|
||||
$ocVersion = oc version | Take-OutputPart -Part 2 | Take-OutputPart -Part 0 -Delimiter "-"
|
||||
return "OpenShift CLI $ocVersion"
|
||||
$ocVersion = oc version -o=json | jq -r '.releaseClientVersion'
|
||||
return $ocVersion
|
||||
}
|
||||
|
||||
function Get-ORASCliVersion {
|
||||
$orasVersion = oras version | Select-String "^Version:" | Take-OutputPart -Part 1
|
||||
return "ORAS CLI $orasVersion"
|
||||
return $orasVersion
|
||||
}
|
||||
|
||||
function Get-VerselCliversion {
|
||||
$result = Get-CommandResult "vercel --version" -Multiline
|
||||
return $result.Output | Select-Object -First 1
|
||||
return $result.Output | Select-Object -Skip 1 -First 1
|
||||
}
|
||||
|
||||
function Get-PulumiVersion {
|
||||
$pulumiVersion = pulumi version | Take-OutputPart -Part 0 -Delimiter "v"
|
||||
return "Pulumi $pulumiVersion"
|
||||
return $pulumiVersion
|
||||
}
|
||||
|
||||
function Get-RVersion {
|
||||
$rVersion = (Get-CommandResult "R --version | grep 'R version'").Output | Take-OutputPart -Part 2
|
||||
return "R $rVersion"
|
||||
return $rVersion
|
||||
}
|
||||
|
||||
function Get-SphinxVersion {
|
||||
$sphinxVersion = searchd -h | Select-Object -First 1 | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "-"
|
||||
return "Sphinx Open Source Search Server $sphinxVersion"
|
||||
return $sphinxVersion
|
||||
}
|
||||
|
||||
function Get-YamllintVersion {
|
||||
return "$(yamllint --version)"
|
||||
return $(yamllint --version) | Take-OutputPart -Part 1
|
||||
}
|
||||
|
||||
function Get-ZstdVersion {
|
||||
$zstdVersion = zstd --version | Take-OutputPart -Part 1 -Delimiter "v" | Take-OutputPart -Part 0 -Delimiter ","
|
||||
return "zstd $zstdVersion (homebrew)"
|
||||
return "$zstdVersion"
|
||||
}
|
||||
|
||||
function Get-YqVersion {
|
||||
$yqVersion = ($(yq -V) -Split " ")[-1]
|
||||
return "yq $yqVersion"
|
||||
$yqVersion = $(yq -V) | Take-OutputPart -Part 3
|
||||
return $yqVersion.TrimStart("v").Trim()
|
||||
}
|
||||
@@ -43,19 +43,13 @@ function Get-Xsp4Version {
|
||||
}
|
||||
}
|
||||
|
||||
function Build-WebServersSection {
|
||||
$servers = @(
|
||||
(Get-ApacheVersion),
|
||||
(Get-NginxVersion)
|
||||
)
|
||||
function Build-WebServersTable {
|
||||
$servers = @()
|
||||
$servers += (Get-ApacheVersion)
|
||||
if (Test-IsUbuntu20) {
|
||||
$servers += (Get-Xsp4Version)
|
||||
}
|
||||
$servers += (Get-NginxVersion)
|
||||
|
||||
$output = ""
|
||||
$output += New-MDHeader "Web Servers" -Level 3
|
||||
$output += $servers | Sort-Object Name | New-MDTable
|
||||
$output += New-MDNewLine
|
||||
|
||||
return $output
|
||||
return $servers
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash -e
|
||||
################################################################################
|
||||
## File: apt-ubuntu-archive.sh
|
||||
## Desc: Script for adding additional apt repo to /etc/apt/sources.list
|
||||
################################################################################
|
||||
|
||||
echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted" | tee -a /etc/apt/sources.list
|
||||
echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs)-updates main restricted" | tee -a /etc/apt/sources.list
|
||||
|
||||
echo "deb http://security.ubuntu.com/ubuntu/ $(lsb_release -cs)-security main restricted" | tee -a /etc/apt/sources.list
|
||||
echo "deb http://security.ubuntu.com/ubuntu/ $(lsb_release -cs)-security universe" | tee -a /etc/apt/sources.list
|
||||
echo "deb http://security.ubuntu.com/ubuntu/ $(lsb_release -cs)-security multiverse" | tee -a /etc/apt/sources.list
|
||||
@@ -14,6 +14,13 @@ echo "APT::Acquire::Retries \"10\";" > /etc/apt/apt.conf.d/80-retries
|
||||
# Configure apt to always assume Y
|
||||
echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes
|
||||
|
||||
# APT understands a field called Phased-Update-Percentage which can be used to control the rollout of a new version. It is an integer between 0 and 100.
|
||||
# In case you have multiple systems that you want to receive the same set of updates,
|
||||
# you can set APT::Machine-ID to a UUID such that they all phase the same,
|
||||
# or set APT::Get::Never-Include-Phased-Updates or APT::Get::Always-Include-Phased-Updates to true such that APT will never/always consider phased updates.
|
||||
# apt-cache policy pkgname
|
||||
echo 'APT::Get::Always-Include-Phased-Updates "true";' > /etc/apt/apt.conf.d/99-phased-updates
|
||||
|
||||
# Fix bad proxy and http headers settings
|
||||
cat <<EOF >> /etc/apt/apt.conf.d/99bad_proxy
|
||||
Acquire::http::Pipeline-Depth 0;
|
||||
@@ -24,11 +31,7 @@ EOF
|
||||
# Uninstall unattended-upgrades
|
||||
apt-get purge unattended-upgrades
|
||||
|
||||
# Need to limit arch for default apt repos due to
|
||||
# https://github.com/actions/virtual-environments/issues/1961
|
||||
sed -i'' -E 's/^deb http:\/\/(azure.archive|security).ubuntu.com/deb [arch=amd64,i386] http:\/\/\1.ubuntu.com/' /etc/apt/sources.list
|
||||
|
||||
echo 'APT sources limited to the actual architectures'
|
||||
echo 'APT sources'
|
||||
cat /etc/apt/sources.list
|
||||
|
||||
apt-get update
|
||||
|
||||
@@ -9,14 +9,8 @@ LSB_RELEASE=$(lsb_release -rs)
|
||||
# Install Microsoft repository
|
||||
wget https://packages.microsoft.com/config/ubuntu/$LSB_RELEASE/packages-microsoft-prod.deb
|
||||
dpkg -i packages-microsoft-prod.deb
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
||||
|
||||
# Install Microsoft GPG public key
|
||||
curl -L https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
|
||||
mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
|
||||
|
||||
# update
|
||||
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
||||
apt-get -yq update
|
||||
apt-get -yq dist-upgrade
|
||||
|
||||
@@ -29,23 +29,27 @@ function Get-CommandResult {
|
||||
}
|
||||
}
|
||||
|
||||
function Get-OSName {
|
||||
lsb_release -ds
|
||||
function Get-OSVersionShort {
|
||||
$(Get-OSVersionFull) | Take-OutputPart -Delimiter '.' -Part 0,1
|
||||
}
|
||||
|
||||
function Get-OSVersionFull {
|
||||
lsb_release -ds | Take-OutputPart -Part 1, 2
|
||||
}
|
||||
|
||||
function Get-KernelVersion {
|
||||
$kernelVersion = uname -r
|
||||
return "Linux kernel version: $kernelVersion"
|
||||
}
|
||||
|
||||
function Test-IsUbuntu18 {
|
||||
return (lsb_release -rs) -eq "18.04"
|
||||
return $kernelVersion
|
||||
}
|
||||
|
||||
function Test-IsUbuntu20 {
|
||||
return (lsb_release -rs) -eq "20.04"
|
||||
}
|
||||
|
||||
function Test-IsUbuntu22 {
|
||||
return (lsb_release -rs) -eq "22.04"
|
||||
}
|
||||
|
||||
function Get-ToolsetContent {
|
||||
$toolset = Join-Path $env:INSTALLER_SCRIPT_FOLDER "toolset.json"
|
||||
Get-Content $toolset -Raw | ConvertFrom-Json
|
||||
@@ -69,7 +73,7 @@ function Get-ToolsetValue {
|
||||
|
||||
function Get-AndroidPackages {
|
||||
$androidSDKManagerPath = "/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager"
|
||||
$androidPackages = & $androidSDKManagerPath --list --verbose
|
||||
$androidPackages = & $androidSDKManagerPath --list --verbose 2>&1
|
||||
return $androidPackages
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,6 @@ function Take-OutputPart {
|
||||
return [string]::Join($Delimiter, $selectedParts)
|
||||
}
|
||||
|
||||
function New-MDNewLine {
|
||||
param (
|
||||
[int] $Count = 1
|
||||
)
|
||||
$newLineSymbol = [System.Environment]::NewLine
|
||||
return $newLineSymbol * $Count
|
||||
}
|
||||
|
||||
function Restore-UserOwner {
|
||||
sudo chown -R ${env:USER}: $env:HOME
|
||||
}
|
||||
@@ -41,118 +33,9 @@ function Get-PathWithLink {
|
||||
return "${inputPath}${link}"
|
||||
}
|
||||
|
||||
function Get-CachedToolInstances
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns hastable of installed cached tools.
|
||||
|
||||
.DESCRIPTION
|
||||
Return hastable that contains versions and architectures for selected cached tool.
|
||||
|
||||
.PARAMETER Name
|
||||
Name of cached tool.
|
||||
|
||||
.PARAMETER VersionCommand
|
||||
Optional parameter. Command to return version of system default tool.
|
||||
|
||||
.EXAMPLE
|
||||
Get-CachedToolInstances -Name "Python" -VersionCommand "--version"
|
||||
|
||||
#>
|
||||
|
||||
param
|
||||
(
|
||||
[String] $Name,
|
||||
[String] $VersionCommand
|
||||
)
|
||||
|
||||
$toolInstances = @()
|
||||
$toolPath = Join-Path -Path $env:AGENT_TOOLSDIRECTORY -ChildPath $Name
|
||||
|
||||
# Get all installed versions from TOOLSDIRECTORY folder
|
||||
$versions = Get-ChildItem $toolPath | Sort-Object { [System.Version]$_.Name }
|
||||
foreach ($version in $versions)
|
||||
{
|
||||
$instanceInfo = @{}
|
||||
|
||||
# Create instance hashtable
|
||||
[string]$instanceInfo.Path = Join-Path -Path $toolPath -ChildPath $version.Name
|
||||
[string]$instanceInfo.Version = $version.Name
|
||||
|
||||
# Get all architectures for current version
|
||||
[array]$instanceInfo.Architecture_Array = Get-ChildItem $version.FullName -Name -Directory | Where-Object { $_ -match "^x[0-9]{2}$" }
|
||||
[string]$instanceInfo.Architecture = $instanceInfo.Architecture_Array -Join ", "
|
||||
|
||||
# Add (default) postfix to version name, in case if current version is in environment path
|
||||
if (-not ([string]::IsNullOrEmpty($VersionCommand)))
|
||||
{
|
||||
$defaultVersion = $(& ($Name.ToLower()) $VersionCommand 2>&1)
|
||||
$defaultToolVersion = $defaultVersion | Select-String -Pattern "\d+\.\d+\.\d+" -AllMatches `
|
||||
| ForEach-Object { $_.Matches.Value }
|
||||
|
||||
if ([version]$version.Name -eq [version]$defaultToolVersion)
|
||||
{
|
||||
$instanceInfo.Version += " (Default)"
|
||||
}
|
||||
}
|
||||
|
||||
$toolInstances += $instanceInfo
|
||||
}
|
||||
|
||||
return $toolInstances
|
||||
}
|
||||
|
||||
function Get-AptSourceRepository {
|
||||
param([String] $PackageName)
|
||||
|
||||
$sourceUrl = Get-Content "$PSScriptRoot/../helpers/apt-sources.txt" | Select-String -Pattern $PackageName | Take-OutputPart -Part (1..3)
|
||||
return $sourceUrl
|
||||
}
|
||||
|
||||
function Test-BlankElement {
|
||||
param(
|
||||
[string] $Markdown
|
||||
)
|
||||
|
||||
$splitByLines = $Markdown.Split("`n")
|
||||
# Validate entry without version
|
||||
$blankVersions = $splitByLines -match "^-" -notmatch "Image Version|MySQL Server|Vcpkg|\d\." | Out-String
|
||||
|
||||
# Validate tables with blank rows
|
||||
$blankRows = ""
|
||||
for($i = 0; $i -lt $splitByLines.Length; $i++) {
|
||||
$addRows= $false
|
||||
$table = @()
|
||||
if ($splitByLines[$i].StartsWith("#") -and $splitByLines[$i+1].StartsWith("|")) {
|
||||
$table += $splitByLines[$i,($i+1),($i+2)]
|
||||
$i += 3
|
||||
$current = $splitByLines[$i]
|
||||
while ($current.StartsWith("|")) {
|
||||
$isBlankRow = $current.Substring(1, $current.LastIndexOf("|") - 2).Split("|").Trim() -contains ""
|
||||
if ($isBlankRow) {
|
||||
$table += $current
|
||||
$addRows = $true
|
||||
}
|
||||
$current = $splitByLines[++$i]
|
||||
}
|
||||
if ($addRows) {
|
||||
$blankRows += $table | Out-String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Display report
|
||||
$isReport = $false
|
||||
if ($blankVersions) {
|
||||
Write-Host "Software list with blank version:`n${blankVersions}"
|
||||
$isReport = $true
|
||||
}
|
||||
if ($blankRows) {
|
||||
Write-Host "Tables with blank rows:`n${blankRows}"
|
||||
$isReport = $true
|
||||
}
|
||||
if ($isReport) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ function Invoke-PesterTests {
|
||||
if (!(Get-Module "Pester")) {
|
||||
Import-Module Pester
|
||||
}
|
||||
|
||||
|
||||
$configuration = [PesterConfiguration] @{
|
||||
Run = @{ Path = $testPath; PassThru = $true }
|
||||
Output = @{ Verbosity = "Detailed" }
|
||||
Output = @{ Verbosity = "Detailed"; RenderMode = "Plaintext" }
|
||||
}
|
||||
if ($TestName) {
|
||||
$configuration.Filter.FullName = $TestName
|
||||
|
||||
@@ -28,15 +28,14 @@ download_with_retries() {
|
||||
set +e
|
||||
http_code=$(eval $COMMAND)
|
||||
exit_code=$?
|
||||
set -e
|
||||
if [ $http_code -eq 200 ] && [ $exit_code -eq 0 ]; then
|
||||
echo "Download completed"
|
||||
return 0
|
||||
else
|
||||
echo "Error — Either HTTP response code for '$URL' is wrong - '$http_code' or exit code is not 0 - '$exit_code'. Waiting $interval seconds before the next attempt, $retries attempts left"
|
||||
sleep 30
|
||||
sleep $interval
|
||||
fi
|
||||
# Enable exit on error back
|
||||
set -e
|
||||
done
|
||||
|
||||
echo "Could not download $URL"
|
||||
@@ -66,3 +65,25 @@ get_toolset_value() {
|
||||
local query=$1
|
||||
echo "$(jq -r "$query" $toolset_path)"
|
||||
}
|
||||
|
||||
get_github_package_download_url() {
|
||||
local REPO_ORG=$1
|
||||
local FILTER=$2
|
||||
local VERSION=$3
|
||||
local SEARCH_IN_COUNT="100"
|
||||
|
||||
json=$(curl -s "https://api.github.com/repos/${REPO_ORG}/releases?per_page=${SEARCH_IN_COUNT}")
|
||||
|
||||
if [ -n "$VERSION" ]; then
|
||||
tagName=$(echo $json | jq -r '.[] | select(.prerelease==false).tag_name' | sort --unique --version-sort | egrep -v ".*-[a-z]|beta" | egrep "\w*${VERSION}" | tail -1)
|
||||
else
|
||||
tagName=$(echo $json | jq -r '.[] | select((.prerelease==false) and (.assets | length > 0)).tag_name' | sort --unique --version-sort | egrep -v ".*-[a-z]|beta" | tail -1)
|
||||
fi
|
||||
|
||||
downloadUrl=$(echo $json | jq -r ".[] | select(.tag_name==\"${tagName}\").assets[].browser_download_url | select(${FILTER})" | head -n 1)
|
||||
if [ -z "$downloadUrl" ]; then
|
||||
echo "Failed to parse a download url for the '${tagName}' tag using '${FILTER}' filter"
|
||||
exit 1
|
||||
fi
|
||||
echo $downloadUrl
|
||||
}
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Temporary fix for the https://github.com/actions/virtual-environments/issues/4732 issue
|
||||
# Taken from the official ubuntu:20.04 docker container
|
||||
### BEGIN INIT INFO
|
||||
# Provides: mysql
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Should-Start: $network $time
|
||||
# Should-Stop: $network $time
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start and stop the mysql database server daemon
|
||||
# Description: Controls the main MySQL database server daemon "mysqld"
|
||||
# and its wrapper script "mysqld_safe".
|
||||
### END INIT INFO
|
||||
#
|
||||
set -e
|
||||
set -u
|
||||
${DEBIAN_SCRIPT_DEBUG:+ set -v -x}
|
||||
|
||||
test -x /usr/bin/mysqld_safe || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)
|
||||
CONF=/etc/mysql/my.cnf
|
||||
MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
|
||||
|
||||
# priority can be overriden and "-s" adds output to stderr
|
||||
ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i"
|
||||
|
||||
# Safeguard (relative paths, core dumps..)
|
||||
cd /
|
||||
umask 077
|
||||
|
||||
# mysqladmin likes to read /root/.my.cnf. This is usually not what I want
|
||||
# as many admins e.g. only store a password without a username there and
|
||||
# so break my scripts.
|
||||
export HOME=/etc/mysql/
|
||||
|
||||
## Fetch a particular option from mysql's invocation.
|
||||
#
|
||||
# Usage: void mysqld_get_param option
|
||||
mysqld_get_param() {
|
||||
/usr/sbin/mysqld --print-defaults \
|
||||
| tr " " "\n" \
|
||||
| grep -- "--$1" \
|
||||
| tail -n 1 \
|
||||
| cut -d= -f2
|
||||
}
|
||||
|
||||
## Do some sanity checks before even trying to start mysqld.
|
||||
sanity_checks() {
|
||||
# check for config file
|
||||
if [ ! -r /etc/mysql/my.cnf ]; then
|
||||
log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz"
|
||||
echo "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER
|
||||
fi
|
||||
|
||||
# check for diskspace shortage
|
||||
datadir=`mysqld_get_param datadir`
|
||||
if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then
|
||||
log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
|
||||
echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
## Checks if there is a server running and if so if it is accessible.
|
||||
#
|
||||
# check_alive insists on a pingable server
|
||||
# check_dead also fails if there is a lost mysqld in the process list
|
||||
#
|
||||
# Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn]
|
||||
mysqld_status () {
|
||||
ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? ))
|
||||
|
||||
ps_alive=0
|
||||
pidfile=`mysqld_get_param pid-file`
|
||||
if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi
|
||||
|
||||
if [ "$1" = "check_alive" -a $ping_alive = 1 ] ||
|
||||
[ "$1" = "check_dead" -a $ping_alive = 0 -a $ps_alive = 0 ]; then
|
||||
return 0 # EXIT_SUCCESS
|
||||
else
|
||||
if [ "$2" = "warn" ]; then
|
||||
echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug
|
||||
fi
|
||||
return 1 # EXIT_FAILURE
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# main()
|
||||
#
|
||||
|
||||
case "${1:-''}" in
|
||||
'start')
|
||||
sanity_checks;
|
||||
# Start daemon
|
||||
log_daemon_msg "Starting MySQL database server" "mysqld"
|
||||
if mysqld_status check_alive nowarn; then
|
||||
log_progress_msg "already running"
|
||||
log_end_msg 0
|
||||
else
|
||||
# Could be removed during boot
|
||||
test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld
|
||||
|
||||
# Start MySQL!
|
||||
su - mysql -s /bin/sh -c "/usr/bin/mysqld_safe > /dev/null 2>&1 &"
|
||||
|
||||
# 6s was reported in #352070 to be too few when using ndbcluster
|
||||
# 14s was reported in #736452 to be too few with large installs
|
||||
for i in $(seq 1 30); do
|
||||
sleep 1
|
||||
if mysqld_status check_alive nowarn ; then break; fi
|
||||
log_progress_msg "."
|
||||
done
|
||||
if mysqld_status check_alive warn; then
|
||||
log_end_msg 0
|
||||
# Now start mysqlcheck or whatever the admin wants.
|
||||
output=$(/etc/mysql/debian-start)
|
||||
[ -n "$output" ] && log_action_msg "$output"
|
||||
else
|
||||
log_end_msg 1
|
||||
log_failure_msg "Please take a look at the syslog"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
'stop')
|
||||
# * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible
|
||||
# at least for cron, we can rely on it here, too. (although we have
|
||||
# to specify it explicit as e.g. sudo environments points to the normal
|
||||
# users home and not /root)
|
||||
log_daemon_msg "Stopping MySQL database server" "mysqld"
|
||||
if ! mysqld_status check_dead nowarn; then
|
||||
set +e
|
||||
shutdown_out=`$MYADMIN shutdown 2>&1`; r=$?
|
||||
set -e
|
||||
if [ "$r" -ne 0 ]; then
|
||||
log_end_msg 1
|
||||
[ "$VERBOSE" != "no" ] && log_failure_msg "Error: $shutdown_out"
|
||||
log_daemon_msg "Killing MySQL database server by signal" "mysqld"
|
||||
killall -15 mysqld
|
||||
server_down=
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
sleep 1
|
||||
if mysqld_status check_dead nowarn; then server_down=1; break; fi
|
||||
done
|
||||
if test -z "$server_down"; then killall -9 mysqld; fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! mysqld_status check_dead warn; then
|
||||
log_end_msg 1
|
||||
log_failure_msg "Please stop MySQL manually and read /usr/share/doc/mysql-server-5.7/README.Debian.gz!"
|
||||
exit -1
|
||||
else
|
||||
log_end_msg 0
|
||||
fi
|
||||
;;
|
||||
|
||||
'restart')
|
||||
set +e; $SELF stop; set -e
|
||||
$SELF start
|
||||
;;
|
||||
|
||||
'reload'|'force-reload')
|
||||
log_daemon_msg "Reloading MySQL database server" "mysqld"
|
||||
$MYADMIN reload
|
||||
log_end_msg 0
|
||||
;;
|
||||
|
||||
'status')
|
||||
if mysqld_status check_alive nowarn; then
|
||||
log_action_msg "$($MYADMIN version)"
|
||||
else
|
||||
log_action_msg "MySQL is stopped."
|
||||
exit 3
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Some success paths end up returning non-zero so exit 0 explicitly. See
|
||||
# bug #739846.
|
||||
exit 0
|
||||
@@ -4,16 +4,16 @@
|
||||
## Desc: Helper functions for installing tools
|
||||
################################################################################
|
||||
|
||||
function isUbuntu18
|
||||
{
|
||||
lsb_release -d | grep -q 'Ubuntu 18'
|
||||
}
|
||||
|
||||
function isUbuntu20
|
||||
{
|
||||
lsb_release -d | grep -q 'Ubuntu 20'
|
||||
}
|
||||
|
||||
function isUbuntu22
|
||||
{
|
||||
lsb_release -d | grep -q 'Ubuntu 22'
|
||||
}
|
||||
|
||||
function getOSVersionLabel
|
||||
{
|
||||
lsb_release -cs
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
# Install Alibaba Cloud CLI
|
||||
URL=$(curl -s https://api.github.com/repos/aliyun/aliyun-cli/releases/latest | jq -r '.assets[].browser_download_url | select(contains("aliyun-cli-linux") and endswith("amd64.tgz"))')
|
||||
download_with_retries $URL "/tmp"
|
||||
downloadUrl="https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz"
|
||||
download_with_retries $downloadUrl "/tmp"
|
||||
tar xzf /tmp/aliyun-cli-linux-*-amd64.tgz
|
||||
mv aliyun /usr/local/bin
|
||||
|
||||
|
||||
@@ -34,24 +34,37 @@ function get_full_ndk_version {
|
||||
# Set env variable for SDK Root (https://developer.android.com/studio/command-line/variables)
|
||||
ANDROID_ROOT=/usr/local/lib/android
|
||||
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
|
||||
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
|
||||
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
|
||||
echo "ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" | tee -a /etc/environment
|
||||
|
||||
# ANDROID_HOME is deprecated, but older versions of Gradle rely on it
|
||||
echo "ANDROID_HOME=${ANDROID_SDK_ROOT}" | tee -a /etc/environment
|
||||
|
||||
# Set env variables for NDK Root
|
||||
echo "ANDROID_NDK_HOME=${ANDROID_NDK_ROOT}" | tee -a /etc/environment
|
||||
echo "ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" | tee -a /etc/environment
|
||||
|
||||
# Create android sdk directory
|
||||
mkdir -p ${ANDROID_SDK_ROOT}
|
||||
|
||||
cmdlineTools="android-cmdline-tools.zip"
|
||||
|
||||
# Download the latest command line tools so that we can accept all of the licenses.
|
||||
# See https://developer.android.com/studio/#command-tools
|
||||
cmdlineTools="android-cmdline-tools.zip"
|
||||
download_with_retries https://dl.google.com/android/repository/commandlinetools-linux-7302050_latest.zip "." $cmdlineTools
|
||||
cmdlineToolsVersion=$(get_toolset_value '.android."cmdline-tools"')
|
||||
if [[ $cmdlineToolsVersion == "latest" ]]; then
|
||||
repositoryXmlUrl="https://dl.google.com/android/repository/repository2-1.xml"
|
||||
download_with_retries $repositoryXmlUrl "/tmp" "repository2-1.xml"
|
||||
cmdlineToolsVersion=$(
|
||||
yq -p=xml \
|
||||
'.sdk-repository.remotePackage[] | select(."+@path" == "cmdline-tools;latest" and .channelRef."+@ref" == "channel-0").archives.archive[].complete.url | select(contains("commandlinetools-linux"))' \
|
||||
/tmp/repository2-1.xml
|
||||
)
|
||||
|
||||
if [[ -z $cmdlineToolsVersion ]]; then
|
||||
echo "Failed to parse latest command-line tools version"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
download_with_retries "https://dl.google.com/android/repository/${cmdlineToolsVersion}" "." $cmdlineTools
|
||||
|
||||
unzip -qq $cmdlineTools -d ${ANDROID_SDK_ROOT}/cmdline-tools
|
||||
# Command line tools need to be placed in ${ANDROID_SDK_ROOT}/sdk/cmdline-tools/latest to determine SDK root
|
||||
mv ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest
|
||||
@@ -74,7 +87,6 @@ addons=$(get_toolset_value '.android.addon_list[]|"add-ons;" + .')
|
||||
additional=$(get_toolset_value '.android.additional_tools[]')
|
||||
ANDROID_NDK_MAJOR_VERSIONS=($(get_toolset_value '.android.ndk.versions[]'))
|
||||
ANDROID_NDK_MAJOR_DEFAULT=$(get_toolset_value '.android.ndk.default')
|
||||
ndkDefaultFullVersion=$(get_full_ndk_version $ANDROID_NDK_MAJOR_DEFAULT)
|
||||
|
||||
components=("${extras[@]}" "${addons[@]}" "${additional[@]}")
|
||||
for ndk_version in "${ANDROID_NDK_MAJOR_VERSIONS[@]}"
|
||||
@@ -83,13 +95,14 @@ do
|
||||
components+=("ndk;$ndk_full_version")
|
||||
done
|
||||
|
||||
# This changes were added due to incompatibility with android ndk-bundle (ndk;22.0.7026061).
|
||||
# Link issue virtual-environments: https://github.com/actions/virtual-environments/issues/2481
|
||||
# Link issue xamarin-android: https://github.com/xamarin/xamarin-android/issues/5526
|
||||
ln -s $ANDROID_SDK_ROOT/ndk/$ndkDefaultFullVersion $ANDROID_NDK_ROOT
|
||||
|
||||
ANDROID_NDK_MAJOR_LATEST=(${ANDROID_NDK_MAJOR_VERSIONS[-1]})
|
||||
ndkDefaultFullVersion=$(get_full_ndk_version $ANDROID_NDK_MAJOR_DEFAULT)
|
||||
ndkLatestFullVersion=$(get_full_ndk_version $ANDROID_NDK_MAJOR_LATEST)
|
||||
ANDROID_NDK="$ANDROID_SDK_ROOT/ndk/$ndkDefaultFullVersion"
|
||||
# ANDROID_NDK, ANDROID_NDK_HOME, and ANDROID_NDK_ROOT variables should be set as many customer builds depend on them https://github.com/actions/runner-images/issues/5879
|
||||
echo "ANDROID_NDK=${ANDROID_NDK}" | tee -a /etc/environment
|
||||
echo "ANDROID_NDK_HOME=${ANDROID_NDK}" | tee -a /etc/environment
|
||||
echo "ANDROID_NDK_ROOT=${ANDROID_NDK}" | tee -a /etc/environment
|
||||
echo "ANDROID_NDK_LATEST_HOME=$ANDROID_SDK_ROOT/ndk/$ndkLatestFullVersion" | tee -a /etc/environment
|
||||
|
||||
availablePlatforms=($($SDKMANAGER --list | sed -n '/Available Packages:/,/^$/p' | grep "platforms;android-[0-9]" | cut -d"|" -f 1))
|
||||
@@ -102,7 +115,7 @@ filter_components_by_version $minimumBuildToolVersion "${availableBuildTools[@]}
|
||||
echo "y" | $SDKMANAGER ${components[@]}
|
||||
|
||||
# Old skdmanager from sdk tools doesn't work with Java > 8, set version 8 explicitly
|
||||
if isUbuntu20; then
|
||||
if isUbuntu20 || isUbuntu22; then
|
||||
sed -i "2i export JAVA_HOME=${JAVA_HOME_8_X64}" ${ANDROID_SDK_ROOT}/tools/bin/sdkmanager
|
||||
fi
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -e
|
||||
################################################################################
|
||||
## File: basic.sh
|
||||
## File: apt-common.sh
|
||||
## Desc: Installs basic command line utilities and dev packages
|
||||
################################################################################
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash -e
|
||||
################################################################################
|
||||
## File: apt-vital.sh
|
||||
## Desc: Installs vital command line utilities
|
||||
################################################################################
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
vital_packages=$(get_toolset_value .apt.vital_packages[])
|
||||
apt-get install -y --no-install-recommends $vital_packages
|
||||
@@ -8,19 +8,9 @@
|
||||
source $HELPER_SCRIPTS/os.sh
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
# Install the AWS CLI v1 Ubuntu18 and AWS CLI v2 on Ubuntu20
|
||||
if isUbuntu20 ; then
|
||||
download_with_retries "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" "/tmp" "awscliv2.zip"
|
||||
unzip -qq /tmp/awscliv2.zip -d /tmp
|
||||
/tmp/aws/install -i /usr/local/aws-cli -b /usr/local/bin
|
||||
fi
|
||||
|
||||
# The installation should be run after python3 is installed as aws-cli V1 dropped python2 support
|
||||
if isUbuntu18 ; then
|
||||
download_with_retries "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" "/tmp" "awscli-bundle.zip"
|
||||
unzip -qq /tmp/awscli-bundle.zip -d /tmp
|
||||
python3 /tmp/awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
|
||||
fi
|
||||
download_with_retries "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" "/tmp" "awscliv2.zip"
|
||||
unzip -qq /tmp/awscliv2.zip -d /tmp
|
||||
/tmp/aws/install -i /usr/local/aws-cli -b /usr/local/bin
|
||||
|
||||
download_with_retries "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" "/tmp" "session-manager-plugin.deb"
|
||||
apt install /tmp/session-manager-plugin.deb
|
||||
|
||||
@@ -10,6 +10,6 @@ source $HELPER_SCRIPTS/install.sh
|
||||
npm install -g @bazel/bazelisk
|
||||
|
||||
# run bazelisk once in order to instal /usr/local/bin/bazel binary
|
||||
bazelisk
|
||||
sudo -u $SUDO_USER bazel version
|
||||
|
||||
invoke_tests "Tools" "Bazel"
|
||||
|
||||
@@ -11,7 +11,7 @@ function InstallClang {
|
||||
local version=$1
|
||||
|
||||
echo "Installing clang-$version..."
|
||||
apt-get install -y "clang-$version" "lldb-$version" "lld-$version" "clang-format-$version"
|
||||
apt-get install -y "clang-$version" "lldb-$version" "lld-$version" "clang-format-$version" "clang-tidy-$version"
|
||||
}
|
||||
|
||||
function SetDefaultClang {
|
||||
@@ -21,6 +21,8 @@ function SetDefaultClang {
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${version} 100
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${version} 100
|
||||
update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-${version} 100
|
||||
update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-${version} 100
|
||||
update-alternatives --install /usr/bin/run-clang-tidy run-clang-tidy /usr/bin/run-clang-tidy-${version} 100
|
||||
}
|
||||
|
||||
versions=$(get_toolset_value '.clang.versions[]')
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
## Desc: Installs CMake
|
||||
################################################################################
|
||||
|
||||
# Source the helpers for use with the script
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
# Test to see if the software in question is already installed, if not install it
|
||||
echo "Checking to see if the installer script has already been run"
|
||||
if command -v cmake; then
|
||||
echo "cmake is already installed"
|
||||
else
|
||||
json=$(curl -s "https://api.github.com/repos/Kitware/CMake/releases")
|
||||
latest_tag=$(echo $json | jq -r '.[] | select(.prerelease==false).tag_name' | sort --unique --version-sort | grep -v "rc" | tail -1)
|
||||
sh_url=$(echo $json | jq -r ".[] | select(.tag_name==\"${latest_tag}\").assets[].browser_download_url | select(endswith(\"inux-x86_64.sh\"))")
|
||||
curl -sL ${sh_url} -o cmakeinstall.sh \
|
||||
downloadUrl=$(get_github_package_download_url "Kitware/CMake" "endswith(\"inux-x86_64.sh\")")
|
||||
curl -sL ${downloadUrl} -o cmakeinstall.sh \
|
||||
&& chmod +x cmakeinstall.sh \
|
||||
&& ./cmakeinstall.sh --prefix=/usr/local --exclude-subdir \
|
||||
&& rm cmakeinstall.sh
|
||||
|
||||
@@ -7,19 +7,39 @@
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
# Retrieve the name of the CodeQL bundle preferred by the Action (in the format codeql-bundle-YYYYMMDD).
|
||||
codeql_bundle_name="$(curl -sSL https://raw.githubusercontent.com/github/codeql-action/v1/src/defaults.json | jq -r .bundleVersion)"
|
||||
# Convert the bundle name to a version number (0.0.0-YYYYMMDD).
|
||||
codeql_bundle_version="0.0.0-${codeql_bundle_name##*-}"
|
||||
base_url="$(curl -sSL https://raw.githubusercontent.com/github/codeql-action/v2/src/defaults.json)"
|
||||
codeql_tag_name="$(echo "$base_url" | jq -r '.bundleVersion')"
|
||||
codeql_cli_version="$(echo "$base_url" | jq -r '.cliVersion')"
|
||||
prior_codeql_tag_name="$(echo "$base_url" | jq -r '.priorBundleVersion')"
|
||||
prior_codeql_cli_version="$(echo "$base_url" | jq -r '.priorCliVersion')"
|
||||
|
||||
extraction_directory="$AGENT_TOOLSDIRECTORY/CodeQL/$codeql_bundle_version/x64"
|
||||
mkdir -p "$extraction_directory"
|
||||
# Convert the tag names to bundles with a version number (x.y.z-YYYYMMDD).
|
||||
codeql_bundle_version="${codeql_cli_version}-${codeql_tag_name##*-}"
|
||||
prior_codeql_bundle_version="${prior_codeql_cli_version}-${prior_codeql_tag_name##*-}"
|
||||
|
||||
echo "Downloading CodeQL bundle $codeql_bundle_version..."
|
||||
download_with_retries "https://github.com/github/codeql-action/releases/download/$codeql_bundle_name/codeql-bundle.tar.gz" "/tmp" "codeql-bundle.tar.gz"
|
||||
tar -xzf "/tmp/codeql-bundle.tar.gz" -C "$extraction_directory"
|
||||
# Download and name both CodeQL bundles.
|
||||
codeql_bundle_versions=("${codeql_bundle_version}" "${prior_codeql_bundle_version}")
|
||||
codeql_tag_names=("${codeql_tag_name}" "${prior_codeql_tag_name}")
|
||||
|
||||
# Touch a special file that indicates to the CodeQL Action that this bundle was baked-in to the hosted runner images.
|
||||
touch "$extraction_directory/pinned-version"
|
||||
for index in "${!codeql_bundle_versions[@]}"; do
|
||||
bundle_version="${codeql_bundle_versions[$index]}"
|
||||
bundle_tag_name="${codeql_tag_names[$index]}"
|
||||
|
||||
echo "Downloading CodeQL bundle $bundle_version..."
|
||||
download_with_retries "https://github.com/github/codeql-action/releases/download/$bundle_tag_name/codeql-bundle.tar.gz" "/tmp" "codeql-bundle.tar.gz"
|
||||
codeql_archive="/tmp/codeql-bundle.tar.gz"
|
||||
|
||||
# Touch a file to indicate to the toolcache that setting up CodeQL is complete.
|
||||
touch "$extraction_directory.complete"
|
||||
codeql_toolcache_path="$AGENT_TOOLSDIRECTORY/CodeQL/$bundle_version/x64"
|
||||
mkdir -p "$codeql_toolcache_path"
|
||||
|
||||
echo "Unpacking the downloaded CodeQL bundle archive..."
|
||||
tar -xzf "$codeql_archive" -C "$codeql_toolcache_path"
|
||||
|
||||
# We only pin the latest version in the toolcache, to support overriding the CodeQL version specified in defaults.json on GitHub Enterprise.
|
||||
if [[ "$bundle_version" == "$codeql_bundle_version" ]]; then
|
||||
touch "$codeql_toolcache_path/pinned-version"
|
||||
fi
|
||||
|
||||
# Touch a file to indicate to the toolcache that setting up CodeQL is complete.
|
||||
touch "$codeql_toolcache_path.complete"
|
||||
done
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# Source the helpers for use with the script
|
||||
source $HELPER_SCRIPTS/os.sh
|
||||
|
||||
# Set ImageVersion and ImageOS env variables
|
||||
echo ImageVersion=$IMAGE_VERSION | tee -a /etc/environment
|
||||
echo ImageOS=$IMAGE_OS | tee -a /etc/environment
|
||||
@@ -7,7 +10,7 @@ echo ImageOS=$IMAGE_OS | tee -a /etc/environment
|
||||
# Set the ACCEPT_EULA variable to Y value to confirm your acceptance of the End-User Licensing Agreement
|
||||
echo ACCEPT_EULA=Y | tee -a /etc/environment
|
||||
|
||||
# This directory is supposed to be created in $HOME and owned by user(https://github.com/actions/virtual-environments/issues/491)
|
||||
# This directory is supposed to be created in $HOME and owned by user(https://github.com/actions/runner-images/issues/491)
|
||||
mkdir -p /etc/skel/.config/configstore
|
||||
echo 'XDG_CONFIG_HOME=$HOME/.config' | tee -a /etc/environment
|
||||
|
||||
@@ -29,6 +32,10 @@ chmod -R 777 $AGENT_TOOLSDIRECTORY
|
||||
# https://www.suse.com/support/kb/doc/?id=000016692
|
||||
echo 'vm.max_map_count=262144' | tee -a /etc/sysctl.conf
|
||||
|
||||
# https://kind.sigs.k8s.io/docs/user/known-issues/#pod-errors-due-to-too-many-open-files
|
||||
echo 'fs.inotify.max_user_watches=655360' | tee -a /etc/sysctl.conf
|
||||
echo 'fs.inotify.max_user_instances=1280' | tee -a /etc/sysctl.conf
|
||||
|
||||
# Create symlink for tests running
|
||||
chmod +x $HELPER_SCRIPTS/invoke-tests.sh
|
||||
ln -s $HELPER_SCRIPTS/invoke-tests.sh /usr/local/bin/invoke_tests
|
||||
@@ -40,3 +47,9 @@ if [[ -f "/etc/fwupd/daemon.conf" ]]; then
|
||||
sed -i 's/UpdateMotd=true/UpdateMotd=false/g' /etc/fwupd/daemon.conf
|
||||
systemctl mask fwupd-refresh.timer
|
||||
fi
|
||||
|
||||
# Disable to load providers
|
||||
# https://github.com/microsoft/azure-pipelines-agent/issues/3834
|
||||
if isUbuntu22; then
|
||||
sed -i 's/openssl_conf = openssl_init/#openssl_conf = openssl_init/g' /etc/ssl/openssl.cnf
|
||||
fi
|
||||
|
||||
@@ -7,22 +7,27 @@
|
||||
source $HELPER_SCRIPTS/os.sh
|
||||
|
||||
install_packages=(podman buildah skopeo)
|
||||
REPO_URL="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable"
|
||||
|
||||
# Install podman, buildah, scopeo container's tools (on Ubuntu20 these tools can be installed without adding new repository)
|
||||
source /etc/os-release
|
||||
sh -c "echo 'deb ${REPO_URL}/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
|
||||
wget -qnv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/x${NAME}_${VERSION_ID}/Release.key -O Release.key
|
||||
apt-key add Release.key
|
||||
apt-get update -qq
|
||||
apt-get -qq -y install ${install_packages[@]}
|
||||
# Packages is available in the official Ubuntu upstream starting from Ubuntu 21
|
||||
if isUbuntu20; then
|
||||
REPO_URL="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable"
|
||||
source /etc/os-release
|
||||
sh -c "echo 'deb ${REPO_URL}/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
|
||||
wget -nv https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/Release.key -O Release.key
|
||||
apt-key add Release.key
|
||||
fi
|
||||
|
||||
# Install podman, buildah, scopeo container's tools
|
||||
apt-get update
|
||||
apt-get -y install ${install_packages[@]}
|
||||
mkdir -p /etc/containers
|
||||
echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" | tee /etc/containers/registries.conf
|
||||
|
||||
# Remove source repo
|
||||
rm /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
|
||||
|
||||
# Document source repo
|
||||
echo "containers $REPO_URL" >> $HELPER_SCRIPTS/apt-sources.txt
|
||||
if isUbuntu20; then
|
||||
# Remove source repo
|
||||
rm /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
|
||||
# Document source repo
|
||||
echo "containers $REPO_URL" >> $HELPER_SCRIPTS/apt-sources.txt
|
||||
fi
|
||||
|
||||
invoke_tests "Tools" "Containers"
|
||||
|
||||
@@ -29,21 +29,34 @@ systemctl is-enabled --quiet docker.service || systemctl enable docker.service
|
||||
sleep 10
|
||||
docker info
|
||||
|
||||
# If credentials are provided, attempt to log into Docker Hub
|
||||
# with a paid account to avoid Docker Hub's rate limit.
|
||||
if [ "${DOCKERHUB_LOGIN}" ] && [ "${DOCKERHUB_PASSWORD}" ]; then
|
||||
docker login --username "${DOCKERHUB_LOGIN}" --password "${DOCKERHUB_PASSWORD}"
|
||||
if [ "${DOCKERHUB_PULL_IMAGES:-yes}" == "yes" ]; then
|
||||
# If credentials are provided, attempt to log into Docker Hub
|
||||
# with a paid account to avoid Docker Hub's rate limit.
|
||||
if [ "${DOCKERHUB_LOGIN}" ] && [ "${DOCKERHUB_PASSWORD}" ]; then
|
||||
docker login --username "${DOCKERHUB_LOGIN}" --password "${DOCKERHUB_PASSWORD}"
|
||||
fi
|
||||
|
||||
# Pull images
|
||||
images=$(get_toolset_value '.docker.images[]')
|
||||
for image in $images; do
|
||||
docker pull "$image"
|
||||
done
|
||||
|
||||
# Always attempt to logout so we do not leave our credentials on the built
|
||||
# image. Logout _should_ return a zero exit code even if no credentials were
|
||||
# stored from earlier.
|
||||
docker logout
|
||||
else
|
||||
echo "Skipping docker images pulling"
|
||||
fi
|
||||
|
||||
# Pull images
|
||||
images=$(get_toolset_value '.docker.images[]')
|
||||
for image in $images; do
|
||||
docker pull "$image"
|
||||
done
|
||||
|
||||
# Always attempt to logout so we do not leave our credentials on the built
|
||||
# image. Logout _should_ return a zero exit code even if no credentials were
|
||||
# stored from earlier.
|
||||
docker logout
|
||||
# Install amazon-ecr-credential-helper
|
||||
aws_latest_release_url="https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/releases/latest"
|
||||
aws_helper_url=$(curl "${authString[@]}" -sL $aws_latest_release_url | jq -r '.body' | awk -F'[()]' '/linux-amd64/ {print $2}')
|
||||
download_with_retries "$aws_helper_url" "/usr/bin" docker-credential-ecr-login
|
||||
chmod +x /usr/bin/docker-credential-ecr-login
|
||||
|
||||
invoke_tests "Tools" "Docker"
|
||||
if [ "${DOCKERHUB_PULL_IMAGES:-yes}" -eq "yes" ]; then
|
||||
invoke_tests "Tools" "Docker images"
|
||||
fi
|
||||
|
||||
@@ -16,6 +16,19 @@ DOTNET_TOOLS=$(get_toolset_value '.dotnet.tools[].name')
|
||||
# Disable telemetry
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
# There is a versions conflict, that leads to
|
||||
# Microsoft <-> Canonical repos dependencies mix up.
|
||||
# Give Microsoft's repo higher priority to avoid collisions.
|
||||
# See: https://github.com/dotnet/core/issues/7699
|
||||
|
||||
cat << EOF > /etc/apt/preferences.d/dotnet
|
||||
Package: *net*
|
||||
Pin: origin packages.microsoft.com
|
||||
Pin-Priority: 1001
|
||||
EOF
|
||||
|
||||
apt-get update
|
||||
|
||||
for latest_package in ${LATEST_DOTNET_PACKAGES[@]}; do
|
||||
echo "Determing if .NET Core ($latest_package) is installed"
|
||||
if ! IsPackageInstalled $latest_package; then
|
||||
@@ -26,18 +39,26 @@ for latest_package in ${LATEST_DOTNET_PACKAGES[@]}; do
|
||||
fi
|
||||
done
|
||||
|
||||
rm /etc/apt/preferences.d/dotnet
|
||||
|
||||
apt-get update
|
||||
|
||||
# Get list of all released SDKs from channels which are not end-of-life or preview
|
||||
sdks=()
|
||||
for version in ${DOTNET_VERSIONS[@]}; do
|
||||
release_url="https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/${version}/releases.json"
|
||||
download_with_retries "${release_url}" "." "${version}.json"
|
||||
releases=$(cat "./${version}.json")
|
||||
sdks=("${sdks[@]}" $(echo "${releases}" | jq '.releases[]' | jq '.sdk.version'))
|
||||
sdks=("${sdks[@]}" $(echo "${releases}" | jq '.releases[]' | jq '.sdks[]?' | jq '.version'))
|
||||
if [[ $version == "6.0" ]]; then
|
||||
sdks=("${sdks[@]}" $(echo "${releases}" | jq -r 'first(.releases[].sdks[]?.version | select(contains("preview") or contains("rc") | not))'))
|
||||
else
|
||||
sdks=("${sdks[@]}" $(echo "${releases}" | jq -r '.releases[].sdk.version | select(contains("preview") or contains("rc") | not)'))
|
||||
sdks=("${sdks[@]}" $(echo "${releases}" | jq -r '.releases[].sdks[]?.version | select(contains("preview") or contains("rc") | not)'))
|
||||
fi
|
||||
rm ./${version}.json
|
||||
done
|
||||
|
||||
sortedSdks=$(echo ${sdks[@]} | tr ' ' '\n' | grep -v preview | grep -v rc | grep -v display | cut -d\" -f2 | sort -r | uniq -w 5)
|
||||
sortedSdks=$(echo ${sdks[@]} | tr ' ' '\n' | sort -r | uniq -w 5)
|
||||
|
||||
extract_dotnet_sdk() {
|
||||
local ARCHIVE_NAME="$1"
|
||||
|
||||
@@ -8,22 +8,22 @@
|
||||
source $HELPER_SCRIPTS/install.sh
|
||||
|
||||
source_list=/etc/apt/sources.list.d/eslerlang.list
|
||||
source_key=/usr/share/keyrings/eslerlang.gpg
|
||||
|
||||
# Install Erlang
|
||||
echo "deb https://binaries.erlang-solutions.com/debian $(lsb_release -cs) contrib" > $source_list
|
||||
wget -q -O - https://binaries.erlang-solutions.com/debian/erlang_solutions.asc | apt-key add -
|
||||
wget -q -O - https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | gpg --dearmor > $source_key
|
||||
echo "deb [signed-by=$source_key] https://packages.erlang-solutions.com/ubuntu $(lsb_release -cs) contrib" > $source_list
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends esl-erlang
|
||||
|
||||
apt-get install --no-install-recommends esl-erlang
|
||||
|
||||
# Install rebar3
|
||||
json=$(curl -sL "https://api.github.com/repos/erlang/rebar3/releases")
|
||||
rebar3Version=$(echo $json | jq -r '.[] | select(.tag_name | contains("-") | not).tag_name' | sort -V | tail -n1)
|
||||
rebar3DownloadUrl=$(echo $json | jq -r ".[] | select(.tag_name==\"$rebar3Version\").assets[].browser_download_url")
|
||||
download_with_retries $rebar3DownloadUrl "/tmp"
|
||||
mv /tmp/rebar3 /usr/local/bin/rebar3
|
||||
rebar3_url="https://github.com/erlang/rebar3/releases/latest/download/rebar3"
|
||||
download_with_retries $rebar3_url "/usr/local/bin" "rebar3"
|
||||
chmod +x /usr/local/bin/rebar3
|
||||
|
||||
# Clean up source list
|
||||
rm $source_list
|
||||
rm $source_key
|
||||
|
||||
invoke_tests "Tools" "erlang"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user