Compare commits

...

151 Commits

Author SHA1 Message Date
Haritha
e7aee39f18 Add conditional check for Pester installation 2025-11-05 12:39:58 -06:00
Haritha
673d91c21a Aligning indentation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-05 12:37:27 -06:00
Haritha
d233269615 Clean up build-tool-packages.yml by removing comments
Removed commented-out test run section from workflow.
2025-11-05 12:18:53 -06:00
Haritha
816a9a3331 Refactor Pester installation step in workflow 2025-11-03 12:07:42 -06:00
Haritha
6c48f687bd Install Pester before running tests
Added a step to install Pester before running tests.
2025-11-03 11:53:28 -06:00
Haritha
e60ec8ae98 Update Pester invocation with configuration options 2025-11-03 11:29:12 -06:00
HarithaVattikuti
db2ae0a36e chore: update macOS version in build workflow to 15-intel 2025-11-03 10:38:51 -06:00
dependabot[bot]
6fdf7f098f Bump actions/download-artifact from 4 to 5 (#88)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-17 14:43:33 -05:00
dependabot[bot]
4ae553a74d Bump actions/checkout from 4 to 5 (#90)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-17 14:42:45 -05:00
Haritha
13ba3fd9e0 Replace self hosted with arm runners (#85) 2025-07-29 12:01:39 -05:00
Ben De St Paer-Gotch
552a1a5fda Merge pull request #86 from actions/nebuk89-patch-1
Update README.md
2025-06-12 10:28:55 +01:00
Ben De St Paer-Gotch
1e5d44c7a5 Update README.md 2025-06-06 11:58:24 +01:00
HarithaVattikuti
817eacd539 Create dependabot.yml (#83) 2025-01-23 09:37:14 -06:00
HarithaVattikuti
933aacb90a Add permission section (#84) 2025-01-16 08:45:16 -06:00
HarithaVattikuti
d3c3feee4b Point to ubuntu-22.04 (#82) 2025-01-08 22:43:01 -06:00
Priya Gupta
4028baf988 Replace deprecated release action with GitHub CLI (#80) 2024-11-12 21:15:45 -06:00
aparnajyothi-y
d30950623a Upgrade the checkout to V4 (#79)
* Update versions to latest

* Update create-pr-to-update-manifest.yml

* Update get-new-tool-versions.yml

* Update get-tools-new-versions.yml

* Update validate-manifest.yml
2024-11-12 21:11:54 -06:00
gowridurgad
16b7940fde Add test jobs for arm64 architecture (#76)
* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* added RUNNER_TYPE

---------

Co-authored-by: aparnajyothi-y <147696841+aparnajyothi-y@users.noreply.github.com>
Co-authored-by: gowridurgad <gowridurga@github.com>
2024-07-09 09:46:50 -05:00
HarithaVattikuti
94d413c5d2 Add win arm64 package availability check (#77) 2024-07-09 09:02:48 -05:00
aparnajyothi-y
6d641c49d7 Fix for windows arm64 node js package (7z) file (#75)
* Update build-tool-packages.yml

* Update and rename build-tool-packages.yml to build-tool-packages.ymll

* Rename build-tool-packages.ymll to build-tool-packages.yml
2024-06-18 12:10:29 -05:00
aparnajyothi-y
447803d00a Architecture update for the test cases of darwin based on macos-14 configuration update (#73)
* macos-latest-large update

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml

* Update build-tool-packages.yml
2024-04-29 08:38:37 -05:00
HarithaVattikuti
b549ccbeee Fix for windows arm64 node js package (7z) file (#72)
* Update build-tool-packages.yml

* Fix for arm64 node
2024-03-28 23:04:25 -05:00
aparnajyothi-y
760646fc29 Add support for arm64 packaging on linux and windows for setup-node (#68)
* arm64 packagging on setup-node

* if condition change

* adding arm64 for entire windows and linux

* error fix

* asser install
2024-03-18 08:21:09 -05:00
Dmitry Shibanov
a8a2c841ba Add automatic build of arm64 for macOS (#66) 2023-11-07 11:51:31 +01:00
Dmitry Shibanov
6fbb1f0f20 Add logic to generate hash file (#65) 2023-09-21 15:34:23 +02:00
Marko Zivic
b964a9871b Merge pull request #62 from erik-bershel/rename-VE-to-RI
Rename 'virtual-environments' repo to 'runner-images'
2022-12-27 10:48:32 +01:00
Marko Zivic
d4cf796ec9 Merge pull request #61 from e-korolevskii/patch-1
Update CODEOWNERS
2022-12-27 09:25:14 +01:00
Erik Bershel
b8e79c3d16 Rename 'virtual-environments' repo to 'runner-images' 2022-12-26 13:23:01 +01:00
Evgenii Korolevskii
b43c6cc8fd Update CODEOWNERS 2022-12-26 13:17:25 +01:00
MaksimZhukov
5810329d19 Introduce reusable workflows into versions repositories (#60) 2022-12-02 12:36:59 +01:00
Aleksandr Chebotov
896369fc7d Replace set output (#59) 2022-10-28 18:08:30 +02:00
Aleksandr Chebotov
d25937e581 Replace var $GITHUB_OUTPUT to $env:GITHUB_OUTPUT (#58) 2022-10-28 17:34:40 +02:00
Aleksandr Chebotov
c08a90cad6 Update workflow tasks (#57) 2022-10-28 14:39:22 +02:00
Aleksandr Chebotov
2c15878a9d Update SLACK_CHANNEL_HOOK secret (#56) 2022-09-08 10:37:51 +02:00
Dusko Dobranic
7b3aff2ad5 Merge pull request #55 from actions/xamarin-update-channel
Update Xamarin channel link
2022-08-10 09:29:20 +02:00
Aleksandr Chebotov
81e64845b7 Update Xamarin channel link 2022-08-10 09:08:34 +02:00
Mikhail Timofeev
56f47ea626 Merge pull request #54 from actions/miketimofeev-patch-1
Change macOS toolset to version 12 in xamarin parser
2022-06-01 17:07:28 +04:00
Mikhail Timofeev
c3143dd446 Update verify-xamarin-parser.psm1 2022-06-01 16:04:34 +03:00
Vladimir Safonkin
31f01aedc7 Get only LTS Node versions from node-versions manifest file (#53)
* Get only LTS Node versions from manifest

* Minor fix
2022-04-28 14:59:24 +02:00
Mikhail Timofeev
e6dbb79745 Merge pull request #52 from actions/shilovmaksim/remove-azdo-related-code
Remove AzDo related code
2022-02-28 10:35:50 +03:00
Maksim Shilov
fe999f6aa6 Remove AzDo related code 2022-02-22 19:02:52 +03:00
Maksim Shilov
33b79844a6 Notifications for Node and Go versions not on image (#44) 2021-12-10 16:44:19 +03:00
Maksim Shilov
de5faa4d9c Adding pypy notifications and optimizing workflow and parsers (#42) 2021-11-11 10:23:00 +03:00
Maksim Shilov
a753279554 New parser for xamarin and python. Reworked workflow with composite actions (#41) 2021-10-27 10:31:19 +03:00
MaksimZhukov
6f1aa3ce73 Merge pull request #40 from nikolai-frolov/remove-token-usage
Remove Access Token usage
2021-10-13 19:43:43 +03:00
nikolai-frolov
e98e069ca6 Remove Access Token usage 2021-10-13 15:56:14 +03:00
MaksimZhukov
8e2a68893f Merge pull request #39 from nikolai-frolov/change-manifest-download
Change way for versions-manifest.json gathering for Validate manifest workflow runs
2021-10-12 17:30:33 +03:00
Nikolai Frolov (Akvelon INC)
359c2548cb Minor code improvement according to comments 2021-10-12 17:19:45 +03:00
Nikolai Frolov (Akvelon INC)
fa49641719 Minor code improvement according to comments 2021-10-12 16:00:52 +03:00
Nikolay Frolov
b5a05e45d5 Change way for versions-manifest.json gathering 2021-10-12 10:35:17 +03:00
MaksimZhukov
e71d476320 Merge pull request #38 from nikolai-frolov/add-retry-strategy
Add retry strategy during manifest download for Validate manifest workflow runs
2021-10-06 17:28:08 +03:00
Nikolay Frolov
7114ad2b94 Add retry strategy 2021-10-05 13:54:40 +03:00
MaksimZhukov
fb0eac418a Merge pull request #36 from Yuriy-Kukushkin/main
Update manifest-validator.ps1 for GH Actions workflow
2021-09-15 10:32:26 +03:00
Yuriy-Kukushkin
f07ff8ddf9 Refactoring 2021-09-09 18:03:55 +03:00
Yuriy-Kukushkin
f72b7a85c7 Update manifest-validator.ps1 2021-09-03 11:55:56 +03:00
Yuriy-Kukushkin
3d09ce1d19 Delete validate_manifest.yml 2021-09-03 11:54:24 +03:00
Yuriy-Kukushkin
a9e00ee513 Merge branch 'actions:main' into main 2021-09-03 11:24:09 +03:00
MaksimZhukov
9f82304f9c Merge pull request #35 from nikita-bykov/get-xamarin-versions
Move get-xamarin-versions pipeline from Azure DevOps
2021-08-26 12:57:28 +03:00
Nikita Bykov
4f7bf4650a Merge branch 'main' of https://github.com/nikita-bykov/versions-package-tools into get-xamarin-versions 2021-08-26 12:54:21 +03:00
MaksimZhukov
1eaa091b65 Merge pull request #34 from actions/v-nibyko/move-get-go-versions
Moving detection pipelines from Azure DevOps
2021-08-26 12:17:09 +03:00
Nikita Bykov
5a00becf47 Update Send Slack notification step to send a custom message 2021-08-25 15:45:33 +03:00
Nikita Bykov
9b849b3d5a Move get-xamarin-versions pipeline 2021-08-23 18:12:30 +03:00
Nikita Bykov
e9ef44e60c Rename version_number variable to TOOL_VERSIONS 2021-08-20 17:40:16 +03:00
Nikita Bykov
6b66054ab6 Add new parameter to send-slack-notification.ps1 and update get-new-tool-versions.ps1 2021-08-19 16:11:48 +03:00
Nikita Bykov
8c62a83204 Add CancelWorkflow method to github-api.psm1 and update get-new-tool-versions.ps1 2021-08-17 17:03:20 +03:00
Yuriy-Kukushkin
ab37396421 Added python validator 2021-08-12 15:54:56 +03:00
Yuriy-Kukushkin
98826eed53 Added node manifest validator 2021-08-12 15:34:50 +03:00
Yuriy-Kukushkin
6147177edd Added Go validator 2021-08-12 15:13:40 +03:00
Yuriy-Kukushkin
2a422a2d52 Create validate_manifest.yml 2021-08-12 10:06:34 +03:00
Maxim Lobanov
46a901fa87 Merge pull request #32 from actions/malob/support-lts
Add generic support for LTS rules
2021-06-16 14:18:58 +03:00
Maxim Lobanov
f19d5f4b3c fix comments 2021-06-16 09:17:33 +00:00
Maxim Lobanov
00039881ba remove comments 2021-06-16 05:48:00 +00:00
Maxim Lobanov
878c283d3b implement pester tests 2021-06-16 05:46:31 +00:00
Maxim Lobanov
41a1acf1a4 first attempt to support lts 2021-06-15 19:24:00 +00:00
Maxim Lobanov
2bd3b2a3c2 Merge pull request #31 from actions/al-cheb/fix-xamarin-tool
Rename toolset for macOS Big Sur
2021-05-20 11:11:02 +03:00
Aleksandr Chebotov
e81db48281 Rename toolset for macOS Big Sur 2021-05-20 11:07:36 +03:00
MaksimZhukov
ab218c2436 Merge pull request #25 from actions/al-cheb/add-xamarin-tool
Add xamarin tool version check
2021-05-05 17:13:29 +03:00
Aleksandr Chebotov
504e746b96 add missing bracket 2021-05-05 16:47:49 +03:00
Maxim Lobanov
4d97edc41a Merge pull request #26 from actions/al-cheb/fix-go-parser
[Go] update regex pattern
2021-04-06 17:46:52 +03:00
Aleksandr Chebotov
80bbe2ac05 update regex pattern 2021-04-06 16:03:15 +03:00
Aleksandr Chebotov
77b53792b3 update message for Xamarin 2021-03-22 21:35:24 +03:00
Aleksandr Chebotov
725c68b777 fix message 2021-03-22 13:44:19 +03:00
Aleksandr Chebotov
81507e485b fix format 2021-03-19 15:45:09 +03:00
Aleksandr Chebotov
7ec75e0761 add xamarin tool version 2021-03-19 15:23:57 +03:00
Maxim Lobanov
590ebcd1ab Merge pull request #24 from actions/add-codeowners
Create CODEOWNERS
2021-01-20 21:38:59 +03:00
Maxim Lobanov
cc2ef5ff7d Update CODEOWNERS 2021-01-11 19:49:58 +03:00
Maxim Lobanov
e37209e8d6 Create CODEOWNERS 2021-01-08 12:36:57 +03:00
Maxim Lobanov
3d7121daba Merge pull request #21 from actions/v-malob/support-go-beta
Support parsing of Go Beta
2020-12-21 23:36:55 +03:00
Maxim Lobanov
f5bdb61b33 Update go-parser.psm1 2020-12-21 20:38:36 +03:00
Maxim Lobanov
96a98e9fb3 Update go-parser.psm1 2020-12-21 20:35:56 +03:00
Maxim Lobanov
5f0e0eebc8 Merge pull request #20 from actions/v-malob/fix-failed-notifications
Cancel builds if new versions are not found instead of failures
2020-12-21 11:06:21 +03:00
Maxim Lobanov
32fbb87915 Update check-versions.yml 2020-12-21 09:23:39 +03:00
Maxim Lobanov
b22990961a Merge pull request #19 from actions/v-malob/fix-yaml-2
Fix YAML dependency
2020-12-16 14:36:39 +03:00
Maxim Lobanov
fc90da9ef1 Update get-tool-versions.yml 2020-12-16 14:33:30 +03:00
Maxim Lobanov
e9cccdf5ed Merge pull request #18 from actions/v-malob/fix-yaml-publish
Fix notifications about new versions
2020-12-16 12:44:16 +03:00
Maxim Lobanov
c2935ecf46 Update get-tool-versions.yml 2020-12-16 12:06:57 +03:00
Maxim Lobanov
0624df7ce9 Update get-tool-versions.yml 2020-12-16 12:05:05 +03:00
Maxim Lobanov
11360e1ff9 polish changes 2020-12-16 12:00:18 +03:00
Maxim Lobanov
ecc77a65f7 Update get-tool-versions-steps.yml 2020-12-16 11:48:43 +03:00
Maxim Lobanov
c304390e31 test 2020-12-16 11:46:22 +03:00
Maxim Lobanov
7e43a35182 Update get-tool-versions-steps.yml 2020-12-16 11:41:58 +03:00
Maxim Lobanov
0d478268bb fix comments 2020-12-16 11:40:43 +03:00
Maxim Lobanov
14f9ca7540 Update get-tool-versions.yml 2020-12-16 11:36:03 +03:00
Maxim Lobanov
1575bb86d1 Update get-tool-versions.yml 2020-12-16 11:35:33 +03:00
Maxim Lobanov
1b966031cc Update get-tool-versions.yml 2020-12-16 11:31:23 +03:00
Maxim Lobanov
4a932e134c Update get-tool-versions.yml 2020-12-16 11:28:26 +03:00
Maxim Lobanov
3e3417e894 Update get-tool-versions.yml 2020-12-16 11:24:39 +03:00
Maxim Lobanov
a5e1431377 Update get-tool-versions.yml 2020-12-16 10:58:06 +03:00
Maxim Lobanov
fb5b7794f0 Update get-tool-versions.yml 2020-12-16 10:57:27 +03:00
Maxim Lobanov
ea9029b06d Update get-tool-versions.yml 2020-12-16 10:54:30 +03:00
Maxim Lobanov
6bc823feae Update get-tool-versions.yml 2020-12-16 10:49:38 +03:00
Maxim Lobanov
84daa05fbc Update get-tool-versions.yml 2020-12-16 10:43:43 +03:00
Maxim Lobanov
e1cbdde483 test 2020-12-16 10:40:09 +03:00
Maxim Lobanov
d61f870ac7 Update get-new-tool-versions.ps1 2020-12-16 10:35:57 +03:00
Maxim Lobanov
e9a19e1251 Update get-tool-versions-steps.yml 2020-12-16 10:31:40 +03:00
Maxim Lobanov
3bfd520dd0 Update get-tool-versions.yml 2020-12-16 10:30:06 +03:00
Maxim Lobanov
840e3a64d3 Update get-tool-versions-steps.yml 2020-12-16 10:26:58 +03:00
Maxim Lobanov
ab240b2f15 Merge pull request #17 from actions/v-malob/python-parser
Rework version grabber and add Python support
2020-12-09 22:25:52 +03:00
Maxim Lobanov
2e6d8df345 fix comments 2020-12-09 15:17:11 +03:00
Maxim Lobanov
5b7cb28e2e fix nitpicks 2020-12-09 14:30:30 +03:00
Maxim Lobanov
4ce7f7efbc Delete get-new-tool-versions.Tests.ps1 2020-12-09 13:32:54 +03:00
Maxim Lobanov
5e5de280d6 fix minor nitpicks 2020-12-09 12:28:15 +03:00
Maxim Lobanov
236d44a167 Update get-tool-versions-steps.yml 2020-12-09 12:07:11 +03:00
Maxim Lobanov
02afcca5c6 Update get-tool-versions-steps.yml 2020-12-09 11:50:51 +03:00
Maxim Lobanov
f4ff9fb93d test 2020-12-09 11:48:13 +03:00
Maxim Lobanov
21cbc1e8ca Update get-tool-versions.yml 2020-12-09 11:15:51 +03:00
Maxim Lobanov
109e6bd009 check condition 2020-12-09 11:15:10 +03:00
Maxim Lobanov
be051a1f12 add parsers 2020-12-09 11:06:04 +03:00
MaksimZhukov
4b0fa42d99 Merge pull request #16 from actions/v-nibyko/boost
Add GetToolDirectory function and fix Get-CommandResult to work properly on Windows
2020-09-09 15:07:13 +03:00
Nikita Bykov
5bcb80c333 refactored function 2020-09-09 12:28:21 +03:00
Nikita Bykov
3f2b844267 added the function GetToolDirectory 2020-09-09 12:18:45 +03:00
Nikita Bykov
7f90ceb82c fixed naming 2020-09-08 14:00:33 +03:00
Nikita Bykov
34c6f7f0ec Resolved comments 2020-09-08 13:59:03 +03:00
Nikita Bykov
94d8a3af83 removed changes 2020-09-08 13:27:15 +03:00
Nikita Bykov
89ebce9383 Fix win-vs-env.psm1 and pester-extensions.psm1 (#15) 2020-09-08 11:39:22 +03:00
MaksimZhukov
f8f76caff1 Merge pull request #14 from actions/v-mazhuk/move-python-versions-ci
Move python-versions CI
2020-08-28 14:01:39 +03:00
MaksimZhukov
8463c1f4c0 Remove redundant string 2020-08-28 12:51:16 +03:00
MaksimZhukov
8e8ae73c1d Fix SYNOPSIS 2020-08-28 11:43:35 +03:00
MaksimZhukov
7aa3827a98 Fix inputs type 2020-08-28 10:16:06 +03:00
MaksimZhukov
2ea972432a Update CreateWorkflowDispatch method 2020-08-27 18:53:42 +03:00
MaksimZhukov
7e2bc9a237 Add create-release.ps1 script 2020-08-27 15:26:35 +03:00
Maxim Lobanov
3b38e3de4c Merge pull request #13 from actions/v-mazhuk/migrate-tools-ci-to-github-actions
Migrate tools CI to GitHub Actions
2020-08-25 11:56:23 +03:00
MaksimZhukov
606411ff6f Update GetPullRequest function 2020-08-24 19:59:55 +03:00
MaksimZhukov
5e417400d9 Add Get-CommandResult function 2020-08-24 18:51:49 +03:00
MaksimZhukov
15842ce7fe Update ShouldReturnZeroExitCode function 2020-08-24 18:40:08 +03:00
MaksimZhukov
45424846c7 Fix typo 2020-08-24 15:36:31 +03:00
MaksimZhukov
ebc70e779a Update github API 2020-08-24 14:53:44 +03:00
MaksimZhukov
347402ff31 Update github API 2020-08-24 14:07:45 +03:00
MaksimZhukov
7a56615638 Migrate tools CI to GA 2020-08-21 19:35:25 +03:00
Maxim Lobanov
68072bedef Merge pull request #12 from actions/v-mazhuk/fix-bug-with-versions-manifest
Build correct manifest json if release includes one asset
2020-07-30 12:07:01 +03:00
MaksimZhukov
377623de6c Fix bug related to versions-manifest-generator 2020-07-29 17:26:07 +03:00
39 changed files with 1361 additions and 660 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @actions/setup-actions-team

View File

@@ -0,0 +1,39 @@
name: 'Send Slack notification'
description: 'SendSlack notification about new versions of a tool'
inputs:
url:
required: true
description: 'Slack channel url'
tool-name:
required: true
description: 'Name of a tool to send notification for. Like Xamarin or Python'
default: 'Xamarin'
tool-version:
required: false
description: 'New versions of a tool'
pipeline-url:
required: false
description: 'Url of a pipeline'
image-url:
required: false
description: 'Image url for message'
default: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'
text:
required: false
description: 'Message text'
add-to-toolset-flag:
required: false
description: 'Flag to use notification for adding new versions to toolset'
runs:
using: "composite"
steps:
- id: send-slack-notification
name: Send Slack notification
shell: pwsh
run: ./get-new-tool-versions/send-slack-notification.ps1 -Url "${{ inputs.url }}" `
-ToolName "${{ inputs.tool-name }}" `
-ToolVersion "${{ inputs.tool-version }}" `
-PipelineUrl "${{ inputs.pipeline-url }}" `
-ImageUrl "${{ inputs.image-url }}" `
-Text "${{ inputs.text }}" `
${{ inputs.add-to-toolset-flag }}

14
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
# Enable version updates for GitHub Actions
- package-ecosystem: 'github-actions'
# Workflow files stored in the default location of `.github/workflows`
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
directory: '/'
schedule:
interval: 'weekly'

View File

@@ -0,0 +1,264 @@
# This reusable workflow is used by actions/*-versions repositories
# It is designed to
# - build and test new versions of a tool (Go, Node)
# - publish a release with a new tool version
# The GITHUB_TOKEN secret is used to trigger workflow runs and publish releases
name: Generate tool packages
on:
workflow_call:
inputs:
tool-name:
description: "Tool name to build and upload. Supported values are: 'go' and 'node'"
required: true
type: string
tool-version:
description: "Tool version to build and upload"
required: true
type: string
publish-release:
description: "Whether to publish releases"
required: true
type: boolean
defaults:
run:
shell: pwsh
jobs:
build:
name: Build ${{ inputs.tool-name }} ${{ inputs.tool-version }} [${{ matrix.platform }}] [${{ matrix.architecture }}]
runs-on: ubuntu-22.04
env:
ARTIFACT_NAME: ${{ inputs.tool-name }}-${{ inputs.tool-version }}-${{ matrix.platform }}-${{ matrix.architecture }}
excludewinarm: ${{ !(inputs.tool-name == 'node' && inputs['tool-version'] < '20.0.0' && matrix.architecture == 'arm64' && matrix.platform == 'win32') }}
strategy:
fail-fast: false
matrix:
platform: [linux, darwin, win32]
architecture: [x64, arm64]
steps:
- name: checkout
if: env.excludewinarm == 'true'
uses: actions/checkout@v5
with:
submodules: true
- name: Build ${{ inputs.tool-name }} ${{ inputs.tool-version }}
if: env.excludewinarm == 'true'
run: |
./builders/build-${{ inputs.tool-name }}.ps1 -Version ${{ inputs.tool-version }} `
-Platform ${{ matrix.platform }} `
-Architecture ${{ matrix.architecture }}
- name: Publish artifact
if: env.excludewinarm == 'true'
uses: actions/upload-artifact@v4
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ runner.temp }}/artifact
test:
name: Test ${{ inputs.tool-name }} ${{ inputs.tool-version }} [${{ matrix.platform }}] [${{ matrix.architecture }}]
needs: build
runs-on: ${{ matrix.os }}
env:
ARTIFACT_NAME: ${{ inputs.tool-name }}-${{ inputs.tool-version }}-${{ matrix.platform }}-${{ matrix.architecture }}
excludewinarm: ${{ !(inputs.tool-name == 'node' && inputs['tool-version'] < '20.0.0' && matrix.architecture == 'arm64' && matrix.platform == 'win32') }}
RUNNER_TYPE: ${{ matrix.runner_type }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux
architecture: x64
- os: macos-15-intel
platform: darwin
architecture: x64
- os: windows-latest
platform: win32
architecture: x64
- os: ubuntu-22.04-arm
platform: linux
architecture: arm64
- os: macos-latest
platform: darwin
architecture: arm64
- os: windows-11-arm
platform: win32
architecture: arm64
steps:
- name: checkout
if: env.excludewinarm == 'true'
uses: actions/checkout@v5
with:
submodules: true
- name: Fully cleanup the toolcache directory before testing
if: env.excludewinarm == 'true'
run: ./helpers/clean-toolcache.ps1 -ToolName "${{ inputs.tool-name }}"
- name: Download artifact
if: env.excludewinarm == 'true'
uses: actions/download-artifact@v5
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ runner.temp }}/${{ env.ARTIFACT_NAME }}
- name: Extract files
if: env.excludewinarm == 'true'
run: |
if ('${{ matrix.platform }}' -eq 'win32') {
if ('${{ inputs.tool-name }}' -eq 'node') {
$artifactName = "${{ env.ARTIFACT_NAME }}.7z"
} elseif ('${{ inputs.tool-name }}' -eq 'go') {
$artifactName = "${{ env.ARTIFACT_NAME }}.zip"
} else {
Write-Host "Unsupported tool - ${{ inputs.tool-name }}"
exit 1
}
7z.exe x "$artifactName" -y | Out-Null
} else {
$artifactName = "${{ env.ARTIFACT_NAME }}.tar.gz"
tar -xzf $artifactName
}
working-directory: ${{ runner.temp }}/${{ env.ARTIFACT_NAME }}
- name: Apply build artifact to the local machine
if: env.excludewinarm == 'true'
run: |
if ('${{ matrix.platform }}' -eq 'win32') { powershell ./setup.ps1 }
else {
sh ./setup.sh
}
working-directory: ${{ runner.temp }}/${{ env.ARTIFACT_NAME }}
- name: Setup Node.js ${{ inputs.tool-version }}
if: env.excludewinarm == 'true' && inputs.tool-name == 'node'
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.tool-version }}
- name: Setup Go ${{ inputs.tool-version }}
if: inputs.tool-name == 'go'
uses: actions/setup-go@v5
with:
go-version: ${{ inputs.tool-version }}
- name: Wait for the logs
if: env.excludewinarm == 'true'
run: |
Write-Host "Fake step that does nothing"
Write-Host "We need it because log from the previous step 'Setup ${{ inputs.tool-name }}' is not available here yet."
Write-Host "In testing step we analyze build log of 'Setup ${{ inputs.tool-name }}' task"
Write-Host "to determine if ${{ inputs.tool-name }} version was consumed from cache or if it was downloaded"
for ($i = 0; $i -lt 200; $i++) { Get-Random }
- name: Ensure Pester Installed
if: env.excludewinarm == 'true'
run: |
$module = Get-Module -ListAvailable -Name Pester
if (-not $module -or ($module.Version -lt [Version]"5.0.0")) {
Install-Module Pester -Force -Scope CurrentUser -SkipPublisherCheck
}
- name: Run tests
if: env.excludewinarm == 'true'
env:
VERSION: ${{ inputs.tool-version }}
run: |
Import-Module Pester
$toolName = (Get-Culture).TextInfo.ToTitleCase("${{ inputs.tool-name }}")
Invoke-Pester -Configuration @{
Run = @{ Path = "./$toolName.Tests.ps1" }
Should = @{ ErrorAction = 'Continue' }
Output = @{ EnableExit = $true }
}
working-directory: ./tests
publish_release:
name: Publish release
if: inputs.publish-release
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v5
- name: Generate release body
id: generate-release-body
run: |
if ('${{ inputs.tool-name }}' -eq 'node') {
$releaseBody = 'Node.js ${{ inputs.tool-version }}'
} else {
$releaseBody = 'Go ${{ inputs.tool-version }}'
}
echo "RELEASE_BODY=$releaseBody" >> $env:GITHUB_OUTPUT
- name: Publish Release
id: create_release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
tag_name="${{ inputs.tool-version }}-${{ github.run_id }}"
gh release create "$tag_name" \
--repo="$GITHUB_REPOSITORY" \
--title="${{ inputs.tool-version }}" \
--notes="${{ steps.generate-release-body.outputs.RELEASE_BODY }}"
release_id=$(gh release view "$tag_name" --repo "$GITHUB_REPOSITORY" --json databaseId --jq '.databaseId')
echo "id=$release_id" >> $GITHUB_OUTPUT
- name: Generate hash for packages
run: |
$childItems = Get-Childitem -Path '.'
$childItems | Foreach-Object {
$packageObj = Get-Childitem -Path $_.FullName | Select-Object -First 1
Write-Host "Package: $($packageObj.Name)"
$actualHash = (Get-FileHash -Path $packageObj.FullName -Algorithm sha256).Hash
$hashString = "$actualHash $($packageObj.Name)"
Write-Host "$hashString"
Add-Content -Path ./hashes.sha256 -Value "$hashString"
}
- name: Upload release assets
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
for (let artifactDir of fs.readdirSync('.')) {
let artifactName = fs.lstatSync(artifactDir).isDirectory() ? fs.readdirSync(`${artifactDir}`)[0] : artifactDir;
console.log(`Upload ${artifactName} asset`);
github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: ${{ steps.create_release.outputs.id }},
name: artifactName,
data: fs.lstatSync(artifactDir).isDirectory() ? fs.readFileSync(`./${artifactDir}/${artifactName}`) : fs.readFileSync(`./${artifactName}`).toString()
});
}
trigger_pr:
name: Trigger "Create Pull Request" workflow
needs: publish_release
runs-on: ubuntu-latest
steps:
- name: Trigger "Create Pull Request" workflow
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'create-pr.yml',
ref: 'main'
});

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v5
- name: Install Pester - name: Install Pester
shell: pwsh shell: pwsh
@@ -20,4 +20,4 @@ jobs:
run: | run: |
Import-Module Pester Import-Module Pester
Import-Module Assert Import-Module Assert
Invoke-Pester -EnableExit Invoke-Pester -EnableExit

View File

@@ -0,0 +1,43 @@
# This reusable workflow is used by actions/*-versions repositories
# It is designed to create a PR with update of versions-manifest.json when a new release is published
# The GITHUB_TOKEN secret is used to create versions-manifest.json and publish related PR
name: Create Pull Request
on:
workflow_call:
inputs:
tool-name:
description: 'Name of the tool for which PR is created'
required: true
type: string
defaults:
run:
shell: pwsh
jobs:
create_pr:
name: Create Pull Request
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Create versions-manifest.json
run: |
./helpers/packages-generation/manifest-generator.ps1 -RepositoryFullName "$env:GITHUB_REPOSITORY" `
-GitHubAccessToken "${{ secrets.GITHUB_TOKEN }}" `
-OutputFile "./versions-manifest.json" `
-ConfigurationFile "./config/${{ inputs.tool-name }}-manifest-config.json"
- name: Create GitHub PR
run: |
$formattedDate = Get-Date -Format "MM/dd/yyyy"
./helpers/github/create-pull-request.ps1 `
-RepositoryFullName "$env:GITHUB_REPOSITORY" `
-AccessToken "${{ secrets.GITHUB_TOKEN }}" `
-BranchName "update-versions-manifest-file" `
-CommitMessage "Update versions-manifest" `
-PullRequestTitle "[versions-manifest] Update for release from ${formattedDate}" `
-PullRequestBody "Update versions-manifest.json for release from ${formattedDate}"

View File

@@ -0,0 +1,109 @@
# This reusable workflow is used by actions/*-versions repositories
# It is designed to check for new versions of a tool (Python, Node, etc.)
# The 'SLACK_CHANNEL_URL' secret must be added to the repository containing the caller workflow
# in order to publish messages to Slack.
# The 'Get Available Tools Versions - Publishing Approval' environment must be created in the repository containing the caller workflow
# The 'trigger_builds' job requires manual approval
# The GITHUB_TOKEN secret is used to cancel and trigger workflow runs
name: Get new tool versions
on:
workflow_call:
inputs:
tool-name:
description: 'Name of the tool for which versions are searched'
required: true
type: string
image-url:
description: 'Tool image to be attached to Slack posts'
required: true
type: string
defaults:
run:
shell: pwsh
jobs:
find_new_versions:
name: Find new versions
runs-on: ubuntu-latest
outputs:
versions_output: ${{ steps.Get_new_versions.outputs.TOOL_VERSIONS }}
steps:
- uses: actions/checkout@v5
with:
submodules: true
- id: Get_new_versions
name: Get new versions
run: ./helpers/get-new-tool-versions/get-new-tool-versions.ps1 -ToolName ${{ inputs.tool-name }}
check_new_versions:
name: Check new versions
runs-on: ubuntu-latest
needs: find_new_versions
env:
TOOL_VERSIONS: ${{needs.find_new_versions.outputs.versions_output}}
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Check Versions
if: env.TOOL_VERSIONS == ''
run: |
Write-Host "No new versions were found"
Import-Module "./helpers/github/github-api.psm1"
$gitHubApi = Get-GitHubApi -RepositoryFullName "$env:GITHUB_REPOSITORY" `
-AccessToken "${{ secrets.GITHUB_TOKEN }}"
$gitHubApi.CancelWorkflow("$env:GITHUB_RUN_ID")
Start-Sleep -Seconds 60
- name: Send Slack notification
run: |
$pipelineUrl = "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID"
$message = "The following versions of '${{ inputs.tool-name }}' are available to upload: ${{ env.TOOL_VERSIONS }}\nLink to the pipeline: $pipelineUrl"
./helpers/get-new-tool-versions/send-slack-notification.ps1 -Url "${{ secrets.SLACK_CHANNEL_URL }}" `
-ToolName "${{ inputs.tool-name }}" `
-ImageUrl "${{ inputs.image-url }}" `
-Text "$message"
trigger_builds:
name: Trigger builds
runs-on: ubuntu-latest
needs: [find_new_versions, check_new_versions]
env:
TOOL_VERSIONS: ${{needs.find_new_versions.outputs.versions_output}}
environment: Get Available Tools Versions - Publishing Approval
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Trigger "Build ${{ inputs.tool-name }} packages" workflow
run: |
$workflowFileName = "build-${{ inputs.tool-name }}-packages.yml".ToLower()
./helpers/github/run-ci-builds.ps1 -RepositoryFullName "$env:GITHUB_REPOSITORY" `
-AccessToken "${{ secrets.GITHUB_TOKEN }}" `
-WorkflowFileName "$workflowFileName" `
-WorkflowDispatchRef "main" `
-ToolVersions "${{ env.TOOL_VERSIONS }}" `
-PublishReleases "true"
check_build:
name: Check build for failures
runs-on: ubuntu-latest
needs: [find_new_versions, check_new_versions, trigger_builds]
if: failure()
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Send Slack notification if build fails
run: |
$pipelineUrl = "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID"
$message = "The build of the '${{ inputs.tool-name }}' detection pipeline failed :progress-error:\nLink to the pipeline: $pipelineUrl"
./helpers/get-new-tool-versions/send-slack-notification.ps1 -Url "${{ secrets.SLACK_CHANNEL_URL }}" `
-ToolName "${{ inputs.tool-name }}" `
-Text "$message" `
-ImageUrl "${{ inputs.image-url }}"

View File

@@ -0,0 +1,89 @@
name: Get tools new versions
on:
schedule:
- cron: '0 8 * * THU'
workflow_dispatch:
defaults:
run:
shell: pwsh
jobs:
find-new-tool-versions:
strategy:
fail-fast: false
matrix:
tool:
- name: 'Xamarin'
image: 'https://avatars.githubusercontent.com/u/790012?s=200&v=4'
releases-url: 'null'
filter-parameter: 'null'
filter-arch: 'null'
- name: 'Python'
image: 'https://avatars.githubusercontent.com/u/1525981?s=200&v=4'
releases-url: 'https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json'
filter-parameter: 'version'
filter-arch: 'x64'
- name: 'PyPy'
image: 'https://avatars.githubusercontent.com/u/318667?s=200&v=4'
releases-url: 'https://downloads.python.org/pypy/versions.json'
filter-parameter: 'python_version'
filter-arch: 'x86'
- name: 'Node'
image: 'https://avatars.githubusercontent.com/u/9950313?s=200&v=4'
releases-url: 'https://raw.githubusercontent.com/actions/node-versions/main/versions-manifest.json'
filter-parameter: 'version'
filter-arch: 'x64'
- name: 'Go'
image: 'https://avatars.githubusercontent.com/u/4314092?s=200&v=4'
releases-url: 'https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json'
filter-parameter: 'version'
filter-arch: 'x64'
name: 'Searching for new versions of ${{ matrix.tool.name }}'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: get-new-tool-versions
name: Get new tool versions
run: |
$versionsOutput = ./get-new-tool-versions/verify-new-tool-version-added-to-image.ps1 `
-ToolName ${{ matrix.tool.name }} `
-ReleasesUrl ${{ matrix.tool.releases-url }} `
-FilterParameter ${{ matrix.tool.filter-parameter }} `
-FilterArch ${{ matrix.tool.filter-arch }}
echo "versions-output=$versionsOutput" >> $env:GITHUB_OUTPUT
- name: Check versions
if: steps.get-new-tool-versions.outputs.versions-output == ''
run: Write-Host "No new versions found"
- uses: ./.github/actions/send-slack-notification
name: Send Slack notification
if: steps.get-new-tool-versions.outputs.versions-output != ''
with:
url: ${{ secrets.SLACK_CHANNEL_HOOK }}
tool-name: '${{ matrix.tool.name }}'
tool-version: ${{ steps.get-new-tool-versions.outputs.versions-output }}
image-url: '${{ matrix.tool.image }}'
add-to-toolset-flag: '-AddToToolsetFlag'
check_build:
name: Check build for failures
runs-on: ubuntu-latest
needs: [find-new-tool-versions]
if: failure()
steps:
- uses: actions/checkout@v5
- id: get-failed-jobs
name: Get failed jobs
run: |
$jobs_url = "$env:GITHUB_API_URL/repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/jobs"
$failedJobs = (Invoke-RestMethod -Uri $jobs_url).jobs |
Where-Object conclusion -eq "failure" |
ForEach-Object {"\n\t" + $_.name.split(" ")[-1] + ": $($_.html_url)"}
echo "failed-jobs=$failedJobs" >> $env:GITHUB_OUTPUT
- uses: ./.github/actions/send-slack-notification
name: Send Slack notification about failure
with:
url: ${{ secrets.SLACK_CHANNEL_HOOK }}
tool-name: 'Tool name'
pipeline-url: '$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID'
text: "Missing toolset tool versions checker pipeline has failed jobs:/n/t${{ steps.get-failed-jobs.outputs.failed-jobs }}"

51
.github/workflows/validate-manifest.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
# This reusable workflow is used by actions/*-versions repositories
# It is designed to validate the versions-manifest.json file
# The 'SLACK_CHANNEL_URL' secret must be added to the repository containing the caller workflow
# in order to publish messages to Slack
name: Validate manifest
on:
workflow_call:
inputs:
tool-name:
description: 'Name of the tool for which manifest is validated'
required: true
type: string
image-url:
description: 'Tool image to be attached to Slack posts'
required: true
type: string
defaults:
run:
shell: pwsh
jobs:
validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Validate manifest
run: .\helpers\packages-generation\manifest-validator.ps1 -ManifestPath '.\versions-manifest.json'
check_build:
name: Check validation for failures
runs-on: ubuntu-latest
needs: [validation]
if: failure()
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Send Slack notification if validation fails
run: |
$pipelineUrl = "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID"
$message = "The validation of ${{ inputs.tool-name }} manifest failed. \nLink to the pipeline: $pipelineUrl"
.\helpers\get-new-tool-versions\send-slack-notification.ps1 -Url "${{ secrets.SLACK_CHANNEL_URL }}" `
-ToolName "${{ inputs.tool-name }}" `
-Text "$message" `
-ImageUrl "${{ inputs.image-url }}"

View File

@@ -1,5 +1,29 @@
# Common tools for generation of packages in the actions/*-versions repositories # Common tools for generation of packages in the actions/*-versions repositories
This repository contains PowerShell modules that are used to generate packages for Actions. The packages are consumed by the images generated through [actions/virtual-environments](https://github.com/actions/virtual-environments) and some of the setup-* Actions This repository contains PowerShell modules that are used to generate packages for Actions. The packages are consumed by the images generated through [actions/runner-images](https://github.com/actions/runner-images) and some of the setup-* Actions
## Contribution ## Recommended permissions
Contributions are welcome! See [Contributor's Guide](./CONTRIBUTING.md) for more details about contribution process and code structure
When using the `versions-package-tools` in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality:
```yaml
permissions:
contents: read # access to read repository's content
actions: read # access to reading actions
```
### Note
Thank you for your interest in this GitHub action, however, right now we are not taking contributions. Add commentMore actionsAdd commentMore actions
We continue to focus our resources on strategic areas that help our customers be successful while making developers' lives easier. While GitHub Actions remains a key part of this vision, we are allocating resources towards other areas of Actions and are not taking contributions to this repository at this time. The GitHub public roadmap is the best place to follow along for any updates on features were working on and what stage theyre in.
We are taking the following steps to better direct requests related to GitHub Actions, including:
1. We will be directing questions and support requests to our [Community Discussions area](https://github.com/orgs/community/discussions/categories/actions)
2. High Priority bugs can be reported through Community Discussions or you can report these to our support team https://support.github.com/contact/bug-report.
3. Security Issues should be handled as per our [security.md](security.md)
We will still provide security updates for this project and fix major breaking changes during this time.
You are welcome to still raise bugs in this repo.

View File

@@ -1,108 +0,0 @@
class AzureDevOpsApi
{
[string] $BaseUrl
[string] $RepoOwner
[object] $AuthHeader
[UInt32] $RetryCount
[UInt32] $RetryIntervalSec
AzureDevOpsApi(
[string] $TeamFoundationCollectionUri,
[string] $ProjectName,
[string] $AccessToken,
[UInt32] $RetryCount,
[UInt32] $RetryIntervalSec
) {
$this.BaseUrl = $this.BuildBaseUrl($TeamFoundationCollectionUri, $ProjectName)
$this.AuthHeader = $this.BuildAuth($AccessToken)
$this.RetryCount = $RetryCount
$this.RetryIntervalSec = $RetryIntervalSec
}
[object] hidden BuildAuth([string]$AccessToken) {
if ([string]::IsNullOrEmpty($AccessToken)) {
return $null
}
return @{
Authorization = "Bearer $AccessToken"
}
}
[string] hidden BuildBaseUrl([string]$TeamFoundationCollectionUri, [string]$ProjectName) {
return "${TeamFoundationCollectionUri}/${ProjectName}/_apis"
}
[object] QueueBuild([string]$ToolVersion, [string]$SourceBranch, [string]$SourceVersion, [UInt32]$DefinitionId){
$url = "build/builds"
# The content of parameters field should be a json string
$buildParameters = @{ VERSION = $ToolVersion } | ConvertTo-Json
$body = @{
definition = @{
id = $DefinitionId
}
sourceBranch = $SourceBranch
sourceVersion = $SourceVersion
parameters = $buildParameters
} | ConvertTo-Json
return $this.InvokeRestMethod($url, 'POST', $body)
}
[object] GetBuildInfo([UInt32]$BuildId){
$url = "build/builds/$BuildId"
return $this.InvokeRestMethod($url, 'GET', $null)
}
[object] UpdateBuildStatus([UInt32]$BuildId, [string]$BuildStatus){
$url = "build/builds/$BuildId"
$body = @{
status = $BuildStatus
} | ConvertTo-Json
return $this.InvokeRestMethod($url, 'PATCH', $body)
}
[string] hidden BuildUrl([string]$Url) {
return "$($this.BaseUrl)/${Url}/?api-version=5.1"
}
[object] hidden InvokeRestMethod(
[string] $Url,
[string] $Method,
[string] $Body
) {
$requestUrl = $this.BuildUrl($Url)
$params = @{
Method = $Method
ContentType = "application/json"
Uri = $requestUrl
Headers = @{}
}
if ($this.AuthHeader) {
$params.Headers += $this.AuthHeader
}
if (![string]::IsNullOrEmpty($body)) {
$params.Body = $Body
}
$params.RetryIntervalSec = $this.RetryIntervalSec
$params.MaximumRetryCount = $this.RetryCount
return Invoke-RestMethod @params
}
}
function Get-AzureDevOpsApi {
param (
[string] $TeamFoundationCollectionUri,
[string] $ProjectName,
[string] $AccessToken,
[UInt32] $RetryCount = 3,
[UInt32] $RetryIntervalSec = 60
)
return [AzureDevOpsApi]::New($TeamFoundationCollectionUri, $ProjectName, $AccessToken, $RetryCount, $RetryIntervalSec)
}

View File

@@ -1,44 +0,0 @@
Import-Module (Join-Path $PSScriptRoot "azure-devops-api.ps1")
class BuildInfo
{
[AzureDevOpsApi] $AzureDevOpsApi
[String] $Name
[UInt32] $Id
[String] $Status
[String] $Result
[String] $Link
BuildInfo([AzureDevOpsApi] $AzureDevOpsApi, [object] $Build)
{
$this.AzureDevOpsApi = $AzureDevOpsApi
$this.Id = $Build.id
$this.Name = $Build.buildNumber
$this.Link = $Build._links.web.href
$this.Status = $Build.status
$this.Result = $Build.result
}
[boolean] IsFinished() {
return ($this.Status -eq "completed") -or ($this.Status -eq "cancelling")
}
[boolean] IsSuccess() {
return $this.Result -eq "succeeded"
}
[void] UpdateBuildInfo() {
$buildInfo = $this.AzureDevOpsApi.GetBuildInfo($this.Id)
$this.Status = $buildInfo.status
$this.Result = $buildInfo.result
}
}
function Get-BuildInfo {
param (
[AzureDevOpsApi] $AzureDevOpsApi,
[object] $Build
)
return [BuildInfo]::New($AzureDevOpsApi, $Build)
}

View File

@@ -1,127 +0,0 @@
param (
[Parameter(Mandatory)] [string] $TeamFoundationCollectionUri,
[Parameter(Mandatory)] [string] $AzureDevOpsProjectName,
[Parameter(Mandatory)] [string] $AzureDevOpsAccessToken,
[Parameter(Mandatory)] [string] $SourceBranch,
[Parameter(Mandatory)] [UInt32] $DefinitionId,
[Parameter(Mandatory)] [string] $SourceVersion,
[Parameter(Mandatory)] [string] $ManifestLink,
[Parameter(Mandatory)] [bool] $WaitForBuilds,
[string] $ToolVersions,
[UInt32] $RetryIntervalSec = 60,
[UInt32] $RetryCount = 3
)
Import-Module (Join-Path $PSScriptRoot "azure-devops-api.ps1")
Import-Module (Join-Path $PSScriptRoot "build-info.ps1")
function Get-ToolVersions {
param (
[Parameter(Mandatory)] [string] $ManifestLink,
[Parameter(Mandatory)] [UInt32] $RetryIntervalSec,
[Parameter(Mandatory)] [UInt32] $Retries,
[string] $ToolVersions
)
[string[]] $versionsList = @()
if ($ToolVersions) {
$versionsList = $ToolVersions.Split(',')
} else {
Write-Host "Get the list of releases from $ManifestLink"
$releases = Invoke-RestMethod $ManifestLink -MaximumRetryCount $Retries -RetryIntervalSec $RetryIntervalSec
$versionsList = $releases.version
}
Write-Host "Versions to build: $versionsList"
return $versionsList
}
function Queue-Builds {
param (
[Parameter(Mandatory)] [AzureDevOpsApi] $AzureDevOpsApi,
[Parameter(Mandatory)] [string[]] $ToolVersions,
[Parameter(Mandatory)] [string] $SourceBranch,
[Parameter(Mandatory)] [string] $SourceVersion,
[Parameter(Mandatory)] [UInt32] $DefinitionId
)
[BuildInfo[]]$queuedBuilds = @()
$ToolVersions | ForEach-Object {
$version = $_.Trim()
Write-Host "Queue build for $version..."
$queuedBuild = $AzureDevOpsApi.QueueBuild($version, $SourceBranch, $SourceVersion, $DefinitionId)
$buildInfo = Get-BuildInfo -AzureDevOpsApi $AzureDevOpsApi -Build $queuedBuild
Write-Host "Queued build: $($buildInfo.Link)"
$queuedBuilds += $buildInfo
}
return $queuedBuilds
}
function Wait-Builds {
param (
[Parameter(Mandatory)] [BuildInfo[]] $Builds,
[Parameter(Mandatory)] [UInt32] $RetryIntervalSec
)
do {
# If build is still running - refresh its status
foreach($build in $builds) {
if (!$build.IsFinished()) {
$build.UpdateBuildInfo()
if ($build.IsFinished()) {
Write-Host "The $($build.Name) build was completed: $($build.Link)"
}
}
}
$runningBuildsCount = ($builds | Where-Object { !$_.IsFinished() }).Length
Start-Sleep -Seconds $RetryIntervalSec
} while($runningBuildsCount -gt 0)
}
function Make-BuildsOutput {
param (
[Parameter(Mandatory)] [BuildInfo[]] $Builds
)
Write-Host "`nBuilds info:"
$builds | Format-Table -AutoSize -Property Name,Id,Status,Result,Link | Out-String -Width 10000
# Return exit code based on status of builds
$failedBuilds = ($builds | Where-Object { !$_.IsSuccess() })
if ($failedBuilds.Length -ne 0) {
Write-Host "##vso[task.logissue type=error;]Builds failed"
$failedBuilds | ForEach-Object -Process { Write-Host "##vso[task.logissue type=error;]Name: $($_.Name); Link: $($_.Link)" }
Write-Host "##vso[task.complete result=Failed]"
} else {
Write-host "##[section]All builds have been passed successfully"
}
}
$azureDevOpsApi = Get-AzureDevOpsApi -TeamFoundationCollectionUri $TeamFoundationCollectionUri `
-ProjectName $AzureDevOpsProjectName `
-AccessToken $AzureDevOpsAccessToken `
-RetryCount $RetryCount `
-RetryIntervalSec $RetryIntervalSec
$toolVersionsList = Get-ToolVersions -ManifestLink $ManifestLink `
-RetryIntervalSec $RetryIntervalSec `
-Retries $RetryCount `
-ToolVersions $ToolVersions
$queuedBuilds = Queue-Builds -AzureDevOpsApi $azureDevOpsApi `
-ToolVersions $toolVersionsList `
-SourceBranch $SourceBranch `
-SourceVersion $SourceVersion `
-DefinitionId $DefinitionId
if ($WaitForBuilds) {
Write-Host "`nWaiting results of builds ..."
Wait-Builds -Builds $queuedBuilds -RetryIntervalSec $RetryIntervalSec
Make-BuildsOutput -Builds $queuedBuilds
}

View File

@@ -1,48 +0,0 @@
name: $(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
schedules:
- cron: "0 3 * * *"
displayName: First daily build
branches:
include:
- main
always: true
- cron: "0 15 * * *"
displayName: Second daily build
branches:
include:
- main
always: true
variables:
PoolName: 'Azure Pipelines'
VmImage: 'ubuntu-18.04'
stages:
- stage: Get_New_Versions
dependsOn: []
jobs:
- job: Get_Tool_Versions
pool:
name: $(PoolName)
vmImage: $(VmImage)
steps:
- template: /azure-pipelines/templates/get-tool-versions-steps.yml
- stage: Trigger_Builds
dependsOn: Get_New_Versions
jobs:
- deployment: Run_Builds
pool:
name: $(PoolName)
vmImage: $(VmImage)
variables:
ToolVersions: $[ stageDependencies.Get_New_Versions.Get_Tool_Versions.outputs['Get_versions.TOOL_VERSIONS'] ]
timeoutInMinutes: 180
environment: 'Get Available Tools Versions - Publishing Approval'
strategy:
runOnce:
deploy:
steps:
- template: /azure-pipelines/templates/run-ci-builds-steps.yml

View File

@@ -1,47 +0,0 @@
steps:
- task: PowerShell@2
displayName: 'Get new versions'
name: 'Get_versions'
inputs:
targetType: filePath
filePath: './get-new-tool-versions/get-new-tool-versions.ps1'
arguments: |
-DistURL "$(DIST_URL)" `
-ManifestLink "$(MANIFEST_URL)" `
-VersionFilterToInclude $(INCLUDE_FILTER) `
-VersionFilterToExclude $(EXCLUDE_FILTER)
- task: PowerShell@2
displayName: 'Cancel build'
condition: and(succeeded(), eq(variables['Get_versions.TOOL_VERSIONS'], ''))
inputs:
TargetType: inline
script: |
Import-Module "./azure-devops/azure-devops-api.ps1"
$azureDevOpsApi = Get-AzureDevOpsApi -TeamFoundationCollectionUri $(System.TeamFoundationCollectionUri) `
-ProjectName $(System.TeamProject) `
-AccessToken $(System.AccessToken)
$AzureDevOpsApi.UpdateBuildStatus($(Build.BuildId), 'Cancelling') | Out-Null
- task: PowerShell@2
displayName: 'Set env variable'
condition: and(succeeded(), ne(variables['Get_versions.TOOL_VERSIONS'], ''))
inputs:
TargetType: inline
script: |
$PipelineUrl = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
Write-Output "##vso[task.setvariable variable=PIPELINE_URL]$PipelineUrl"
- task: PowerShell@2
displayName: 'Send Slack notification'
condition: and(succeeded(), ne(variables['Get_versions.TOOL_VERSIONS'], ''))
inputs:
targetType: filePath
filePath: './get-new-tool-versions/send-slack-notification.ps1'
arguments: |
-Url "$(SLACK_CHANNEL_URL)" `
-ToolName "$(TOOL_NAME)" `
-ToolVersion "$(Get_versions.TOOL_VERSIONS)" `
-PipelineUrl "$(PIPELINE_URL)" `
-ImageUrl "$(IMAGE_URL)"

View File

@@ -1,29 +0,0 @@
steps:
- checkout: self
- task: PowerShell@2
displayName: 'Get source version'
inputs:
TargetType: inline
script: |
$url = "https://api.github.com/repos/$(REPOSITORY)/commits/$(BRANCH)"
$commit = Invoke-RestMethod -Uri $url -Method "GET"
Write-Output "##vso[task.setvariable variable=COMMIT_SHA]$($commit.sha)"
- task: PowerShell@2
displayName: 'Run builds'
inputs:
targetType: filePath
filePath: './azure-devops/run-ci-builds.ps1'
arguments: |
-TeamFoundationCollectionUri $(System.TeamFoundationCollectionUri) `
-AzureDevOpsProjectName $(System.TeamProject) `
-AzureDevOpsAccessToken $(System.AccessToken) `
-SourceBranch $(BRANCH) `
-DefinitionId $(DEFINITION_ID) `
-SourceVersion $(COMMIT_SHA) `
-ManifestLink $(MANIFEST_URL) `
-WaitForBuilds $(WAIT_FOR_BUILDS) `
-ToolVersions "$(ToolVersions)" `
-RetryIntervalSec $(INTERVAL_SEC) `
-RetryCount $(RETRY_COUNT)

View File

@@ -3,6 +3,11 @@ param (
) )
$targetPath = $env:AGENT_TOOLSDIRECTORY $targetPath = $env:AGENT_TOOLSDIRECTORY
if ([string]::IsNullOrEmpty($targetPath)) {
# GitHub Windows images don't have `AGENT_TOOLSDIRECTORY` variable
$targetPath = $env:RUNNER_TOOL_CACHE
}
if ($ToolName) { if ($ToolName) {
$targetPath = Join-Path $targetPath $ToolName $targetPath = Join-Path $targetPath $ToolName
} }

View File

@@ -83,3 +83,26 @@ function IsNixPlatform {
return ($Platform -match "macos") -or ($Platform -match "darwin") -or ($Platform -match "ubuntu") -or ($Platform -match "linux") return ($Platform -match "macos") -or ($Platform -match "darwin") -or ($Platform -match "ubuntu") -or ($Platform -match "linux")
} }
<#
.SYNOPSIS
Get root directory of selected tool
#>
function GetToolDirectory {
param(
[Parameter(Mandatory=$true)]
[String]$ToolName,
[Parameter(Mandatory=$true)]
[String]$Version,
[Parameter(Mandatory=$true)]
[String]$Architecture
)
$targetPath = $env:AGENT_TOOLSDIRECTORY
if ([string]::IsNullOrEmpty($targetPath)) {
# GitHub Windows images don't have `AGENT_TOOLSDIRECTORY` variable
$targetPath = $env:RUNNER_TOOL_CACHE
}
$ToolcachePath = Join-Path -Path $targetPath -ChildPath $ToolName
$ToolcacheVersionPath = Join-Path -Path $ToolcachePath -ChildPath $Version
return Join-Path $ToolcacheVersionPath $Architecture
}

View File

@@ -1,93 +0,0 @@
#Requires -Modules Pester
Import-Module (Join-Path $PSScriptRoot "helpers.psm1") -Force
Describe "Validate-FiltersFormat" {
It "Filter with word" {
{ Validate-FiltersFormat -Filters @("1two.2") } | Should -Throw "Invalid filter format"
}
It "Filter with non-word character" {
{ Validate-FiltersFormat -Filters @("1,.2") } | Should -Throw "Invalid filter format"
}
It "Valid filters" {
{ Validate-FiltersFormat -Filters @("*", "1", "1.*", "1.2", "1.2.*") } | Should -Not -Throw "Invalid filter format"
}
}
Describe "Format-Versions" {
It "Clean versions" {
$actualOutput = Format-Versions -Versions @("14.2.0", "1.14.0")
$expectedOutput = @("14.2.0", "1.14.0")
$actualOutput | Should -Be $expectedOutput
}
It "Versions with prefixes" {
$actualOutput = Format-Versions -Versions @("v14.2.0", "go1.14.0")
$expectedOutput = @("14.2.0", "1.14.0")
$actualOutput | Should -Be $expectedOutput
}
It "Skip beta and rc versions" {
$actualOutput = Format-Versions -Versions @("14.2.0-beta", "v1.14.0-rc-1")
$expectedOutput = @()
$actualOutput | Should -Be $expectedOutput
}
It "Short version" {
$actualOutput = Format-Versions -Versions @("14.2", "v2.0")
$expectedOutput = @("14.2.0", "2.0.0")
$actualOutput | Should -Be $expectedOutput
}
It "Skip versions with 1 digit" {
$actualOutput = Format-Versions -Versions @("14", "v2")
$expectedOutput = @()
$actualOutput | Should -Be $expectedOutput
}
}
Describe "Select-VersionsByFilter" {
$inputVersions = @("8.2.1", "9.3.3", "10.0.2", "10.0.3", "10.5.6", "12.4.3", "12.5.1", "14.2.0")
It "Include filter only" {
$includeFilters = @("8.*", "14.*")
$excludeFilters = @()
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("8.2.1", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
It "Include and exclude filters" {
$includeFilters = @("10.*", "12.*")
$excludeFilters = @("10.0.*", "12.4.3")
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("10.5.6", "12.5.1")
$actualOutput | Should -Be $expectedOutput
}
It "Exclude filter only" {
$includeFilters = @()
$excludeFilters = @("10.*", "12.*")
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("8.2.1", "9.3.3", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
It "Include and exclude filters are empty" {
$actualOutput = Select-VersionsByFilter -Versions $inputVersions
$expectedOutput = @("8.2.1", "9.3.3", "10.0.2", "10.0.3", "10.5.6", "12.4.3", "12.5.1", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
}
Describe "Skip-ExistingVersions" {
It "Substract versions correctly" {
$distInput = @("14.2.0", "14.3.0", "14.4.0", "14.4.1")
$manifestInput = @("12.0.0", "14.2.0", "14.4.0")
$actualOutput = Skip-ExistingVersions -VersionsFromDist $distInput -VersionsFromManifest $manifestInput
$expectedOutput = @("14.3.0", "14.4.1")
$actualOutput | Should -Be $expectedOutput
}
}

View File

@@ -2,79 +2,26 @@
.SYNOPSIS .SYNOPSIS
Check and return list of new available tool versions Check and return list of new available tool versions
.PARAMETER DistURL .PARAMETER ToolName
Required parameter. Link to the json file included all available tool versions Required parameter. The name of tool for which parser is available (Node, Go, Python)
.PARAMETER ManifestLink
Required parameter. Link to the the version-manifest.json file
.PARAMETER VersionFilterToInclude
Optional parameter. List of filters to include particular versions
.PARAMETER VersionFilterToExclude
Optional parameter. List of filters to exclude particular versions
.PARAMETER RetryIntervalSec
Optional parameter. Retry interval in seconds
.PARAMETER RetryCount
Optional parameter. Retry count
#> #>
param ( param (
[Parameter(Mandatory)] [string] $DistURL, [Parameter(Mandatory)] [string] $ToolName
[Parameter(Mandatory)] [string] $ManifestLink,
[string[]] $VersionFilterToInclude,
[string[]] $VersionFilterToExclude,
[UInt32] $RetryIntervalSec = 60,
[UInt32] $RetryCount = 3
) )
Import-Module (Join-Path $PSScriptRoot "helpers.psm1") Import-Module "$PSScriptRoot/parsers/parsers-factory.psm1"
function Get-VersionsByUrl { $ToolVersionParser = Get-ToolVersionsParser -ToolName $ToolName
param ( $VersionsFromDist = $ToolVersionParser.GetAvailableVersions()
[Parameter(Mandatory)] [string] $ToolPackagesUrl, $VersionsFromManifest = $ToolVersionParser.GetUploadedVersions()
[Parameter(Mandatory)] [UInt32] $RetryIntervalSec,
[Parameter(Mandatory)] [UInt32] $RetryCount
)
$packages = Invoke-RestMethod $ToolPackagesUrl -MaximumRetryCount $RetryCount -RetryIntervalSec $RetryIntervalSec $VersionsToBuild = $VersionsFromDist | Where-Object { $VersionsFromManifest -notcontains $_ }
return $packages.version
}
if ($VersionFilterToInclude) { if ($VersionsToBuild) {
Validate-FiltersFormat -Filters $VersionFilterToInclude $availableVersions = $VersionsToBuild -join ", "
} Write-Host "The following versions are available to build:`n${availableVersions}"
"TOOL_VERSIONS=${availableVersions}" >> $env:GITHUB_OUTPUT
if ($VersionFilterToExclude) {
Validate-FiltersFormat -Filters $VersionFilterToExclude
}
Write-Host "Get the packages list from $DistURL"
$versionsFromDist = Get-VersionsByUrl -ToolPackagesUrl $DistURL `
-RetryIntervalSec $RetryIntervalSec `
-RetryCount $RetryCount
Write-Host "Get the packages list from $ManifestLink"
[Version[]] $versionsFromManifest = Get-VersionsByUrl -ToolPackagesUrl $ManifestLink `
-RetryIntervalSec $RetryIntervalSec `
-RetryCount $RetryCount
[Version[]] $formattedVersions = Format-Versions -Versions $versionsFromDist
$formattedVersions = Select-VersionsByFilter -Versions $formattedVersions `
-IncludeFilters $VersionFilterToInclude `
-ExcludeFilters $VersionFilterToExclude
if (-not $formattedVersions) {
Write-Host "Couldn't find available versions with current filters"
exit 1
}
$versionsToBuild = Skip-ExistingVersions -VersionsFromManifest $versionsFromManifest `
-VersionsFromDist $formattedVersions
if ($versionsToBuild) {
$availableVersions = $versionsToBuild -join ","
$toolVersions = $availableVersions.Replace(",",", ")
Write-Host "The following versions are available to build:`n$toolVersions"
Write-Output "##vso[task.setvariable variable=TOOL_VERSIONS;isOutput=true]$toolVersions"
} else { } else {
Write-Host "There aren't versions to build" Write-Host "There aren't versions to build"
} }

View File

@@ -1,17 +1,3 @@
function Validate-FiltersFormat {
param (
[Parameter(Mandatory)] [string[]] $Filters
)
foreach($filter in $Filters) {
$filter.Split('.') | ForEach-Object {
if (($_ -notmatch '^\d+$') -and ($_ -ne '*')) {
throw "Invalid filter format - $filter"
}
}
}
}
function Format-Versions { function Format-Versions {
param ( param (
[Parameter(Mandatory)] [string[]] $Versions [Parameter(Mandatory)] [string[]] $Versions

View File

@@ -0,0 +1,31 @@
class BaseVersionsParser {
[Int32]$ApiRetryCount = 3
[Int32]$ApiRetryIntervalSeconds = 60
[SemVer[]] GetAvailableVersions() {
$allVersionsRaw = $this.ParseAllAvailableVersions()
$allVersions = $allVersionsRaw | ForEach-Object { $this.FormatVersion($_) }
$filteredVersions = $allVersions | Where-Object { $this.ShouldIncludeVersion($_) }
return $filteredVersions
}
[SemVer[]] GetUploadedVersions() {
throw "Method is not implemented in base class"
}
hidden [SemVer[]] ParseAllAvailableVersions() {
throw "Method is not implemented in base class"
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
throw "Method is not implemented in base class"
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
throw "Method is not implemented in base class"
}
hidden [string] BuildGitHubFileUrl($OrganizationName, $RepositoryName, $BranchName, $FilePath) {
return "https://raw.githubusercontent.com/${OrganizationName}/${RepositoryName}/${BranchName}/${FilePath}"
}
}

View File

@@ -0,0 +1,30 @@
using module "./base-parser.psm1"
class GoVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "go-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$url = "https://golang.org/dl/?mode=json&include=all"
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$cleanVersion = $VersionSpec -replace "^go", ""
$semanticVersion = $cleanVersion -replace '(\d+\.\d+\.?\d*?)((?:alpha|beta|rc))(\d*)', '$1-$2.$3'
return [SemVer]$semanticVersion
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
if ($Version.PreReleaseLabel) {
return $false
}
# For Go, we include all versions greater than 1.12
return $Version -gt [SemVer]"1.12.0"
}
}

View File

@@ -0,0 +1,30 @@
using module "./base-parser.psm1"
class NodeVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "node-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$url = "https://nodejs.org/dist/index.json"
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$cleanVersion = $VersionSpec -replace "^v", ""
return [SemVer]$cleanVersion
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
if ($Version.Major -lt 8) {
return $false
}
# For Node.JS, we should include all LTS versions (all even-numbered releases)
# https://nodejs.org/en/about/releases/
return $Version.Major % 2 -eq 0
}
}

View File

@@ -0,0 +1,19 @@
using module "./node-parser.psm1"
using module "./go-parser.psm1"
using module "./python-parser.psm1"
function Get-ToolVersionsParser {
param(
[Parameter(Mandatory)]
[string]$ToolName
)
switch ($ToolName) {
"Node" { return [NodeVersionsParser]::New() }
"Go" { return [GoVersionsParser]::New() }
"Python" { return [PythonVersionsParser]::New() }
Default {
throw "Unknown tool name"
}
}
}

View File

@@ -0,0 +1,53 @@
using module "./base-parser.psm1"
class PythonVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "python-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$stableVersionsUrl = "https://www.python.org/ftp/python"
$stableVersionsHtmlRaw = Invoke-WebRequest $stableVersionsUrl -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
$stableVersionsList = $stableVersionsHtmlRaw.Links.href | Where-Object {
$parsed = $null
return $_.EndsWith("/") -and [SemVer]::TryParse($_.Replace("/", ""), [ref]$parsed)
}
return $stableVersionsList | ForEach-Object {
$subVersionsUrl = "${stableVersionsUrl}/${_}"
$subVersionsHtmlRaw = Invoke-WebRequest $subVersionsUrl -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $subVersionsHtmlRaw.Links.href | ForEach-Object {
if ($_ -match "^Python-(\d+\.\d+\.\d+[a-z]{0,2}\d*)\.tgz$") {
return $Matches[1]
}
}
}
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$VersionSpec -match "^(\d+)\.(\d+)\.(\d+)([a-z]{1,2})?(\d+)?$"
if ($Matches.Count -gt 4) {
$VersionLabel = "{0}.{1}" -f $this.ConvertPythonLabel($Matches[4]), $Matches[5]
return [SemVer]::new($Matches[1], $Matches[2], $Matches[3], $VersionLabel)
}
return [SemVer]::new($Matches[1], $Matches[2], $Matches[3])
}
hidden [string] ConvertPythonLabel([string]$Label) {
switch ($Label) {
"a" { return "alpha" }
"b" { return "beta" }
}
return $Label
}
[bool] ShouldIncludeVersion([SemVer]$Version) {
# For Python, we include all versions greater than 3.9.0
return $Version -gt [SemVer]"3.9.0"
}
}

View File

@@ -0,0 +1,27 @@
function Search-ToolsVersionsNotOnImage {
param (
[string]$ToolName,
[string]$ReleasesUrl,
[string]$FilterParameter,
[string]$FilterArch
)
$stableReleases = (Invoke-RestMethod $ReleasesUrl) | Where-Object stable -eq $true
$stableReleaseVersions = $stableReleases | ForEach-Object {
if ($ToolName -eq "Node") {
if ($_.lts) {
$_.$FilterParameter.split(".")[0] + ".0"
}
} else {
$_.$FilterParameter.split(".")[0,1] -join"."
}
} | Select-Object -Unique
$toolsetUrl = "https://raw.githubusercontent.com/actions/runner-images/main/images/win/toolsets/toolset-2022.json"
$latestMinorVersion = (Invoke-RestMethod $toolsetUrl).toolcache |
Where-Object {$_.name -eq $ToolName -and $_.arch -eq $FilterArch} |
ForEach-Object {$_.versions.Replace("*","0")} |
Select-Object -Last 1
$versionsToAdd = $stableReleaseVersions | Where-Object {[version]$_ -gt [version]$latestMinorVersion}
return $versionsToAdd
}

View File

@@ -0,0 +1,19 @@
function Search-XamarinVersionsNotOnImage {
param (
[string]$ReleasesUrl,
[array]$FilterProducts
)
$xamarinReleases = (Invoke-RestMethod $ReleasesUrl).items
$filteredReleases = $xamarinReleases | Where-Object {$_.name -in $FilterProducts.name} | Sort-Object name | Select-Object name, version
$toolsetUrl = "https://raw.githubusercontent.com/actions/runner-images/main/images/macos/toolsets/toolset-12.json"
$uploadedReleases = (Invoke-RestMethod $toolsetUrl).xamarin
$releasesOnImage = @()
foreach ($FilterProduct in $FilterProducts) {
$releasesOnImage += @{$FilterProduct.name = $uploadedReleases.($FilterProduct.property)}
}
$versionsToAdd = $filteredReleases | Where-Object {$releasesOnImage.($_.name) -notcontains $_.version} | ForEach-Object {[string]::Empty} {
'{0,-15} : {1}' -f $_.name, $_.version
}
return $versionsToAdd
}

View File

@@ -7,11 +7,15 @@ Required parameter. Incoming Webhook URL to post a message
.PARAMETER ToolName .PARAMETER ToolName
Required parameter. The name of tool Required parameter. The name of tool
.PARAMETER ToolVersion .PARAMETER ToolVersion
Required parameter. Specifies the version of tool Optional parameter. Specifies the version of tool
.PARAMETER PipelineUrl .PARAMETER PipelineUrl
Required parameter. The pipeline URL Optional parameter. The pipeline URL
.PARAMETER ImageUrl .PARAMETER ImageUrl
Optional parameter. The image URL Optional parameter. The image URL
.PARAMETER Text
Optional parameter. The message to post
.PARAMETER AddToToolsetFlag
Optional parameter. Flag to alternate message text for adding new version of a tool to toolset notification
#> #>
param( param(
@@ -23,22 +27,28 @@ param(
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[System.String]$ToolName, [System.String]$ToolName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[System.String]$ToolVersion, [System.String]$ToolVersion,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[System.String]$PipelineUrl, [System.String]$PipelineUrl,
[System.String]$ImageUrl = 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
[System.String]$ImageUrl = 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png' [System.String]$Text,
[Switch]$AddToToolsetFlag
) )
# Import helpers module # Import helpers module
Import-Module $PSScriptRoot/helpers.psm1 -DisableNameChecking Import-Module $PSScriptRoot/helpers.psm1 -DisableNameChecking
# Create JSON body # Create JSON body
$text = "The following versions of '$toolName' are available to upload: $toolVersion\nLink to the pipeline: $pipelineUrl" if ([string]::IsNullOrWhiteSpace($Text)) {
if ($AddToToolsetFlag) {
$Text = "The following versions of '$toolName' are available, consider adding them to toolset: $toolVersion"
} else {
$Text = "The following versions of '$toolName' are available to upload: $toolVersion"
}
}
if (-not ([string]::IsNullOrWhiteSpace($PipelineUrl))) {
$Text += "\nLink to the pipeline: $pipelineUrl"
}
$jsonBodyMessage = @" $jsonBodyMessage = @"
{ {
"blocks": [ "blocks": [
@@ -46,7 +56,7 @@ $jsonBodyMessage = @"
"type": "section", "type": "section",
"text": { "text": {
"type": "mrkdwn", "type": "mrkdwn",
"text": "$text" "text": "$Text"
}, },
"accessory": { "accessory": {
"type": "image", "type": "image",

View File

@@ -0,0 +1,38 @@
<#
.SYNOPSIS
Check and return list of new available tool versions that not added to toolsets yet
.PARAMETER ToolName
Required parameter. The name of tool for which parser is available (Python, Xamarin, PyPy, Node, Go)
#>
param (
[Parameter(Mandatory)]
[ValidateSet("Python", "Xamarin", "PyPy", "Node", "Go")]
[string] $ToolName,
[string] $ReleasesUrl,
[string] $FilterParameter,
[string] $FilterArch
)
Get-ChildItem "$PSScriptRoot/parsers/verify-added-to-image/" | ForEach-Object {Import-Module $_.FullName}
if ($ToolName -in "Python", "PyPy", "Node", "Go") {
$versionsToAdd = Search-ToolsVersionsNotOnImage -ToolName $ToolName -ReleasesUrl $ReleasesUrl -FilterParameter $FilterParameter -FilterArch $FilterArch
}
if ($ToolName -eq "Xamarin") {
$xamarinReleases = "http://aka.ms/manifest/stable-2022"
$xamarinProducts = @(
[PSCustomObject] @{name = 'Mono Framework'; property = 'mono-versions'}
[PSCustomObject] @{name = 'Xamarin.Android'; property = 'android-versions'}
[PSCustomObject] @{name = 'Xamarin.iOS'; property = 'ios-versions'}
[PSCustomObject] @{name = 'Xamarin.Mac'; property = 'mac-versions'}
)
$versionsToAdd = Search-XamarinVersionsNotOnImage -ReleasesUrl $xamarinReleases -FilterProducts $xamarinProducts
$joinChars = "\n\t"
}
$versionsToAdd = $versionsToAdd -join $joinChars
return $versionsToAdd

View File

@@ -2,10 +2,8 @@
.SYNOPSIS .SYNOPSIS
Create commit with all unstaged changes in repository and create pull-request Create commit with all unstaged changes in repository and create pull-request
.PARAMETER RepositoryOwner .PARAMETER RepositoryFullName
Required parameter. The organization which tool repository belongs Required parameter. The owner and repository name. For example, 'actions/versions-package-tools'
.PARAMETER RepositoryName
Optional parameter. The name of tool repository
.PARAMETER AccessToken .PARAMETER AccessToken
Required parameter. PAT Token to authorize Required parameter. PAT Token to authorize
.PARAMETER BranchName .PARAMETER BranchName
@@ -18,8 +16,7 @@ Required parameter. The title of pull-request
Required parameter. The description of pull-request Required parameter. The description of pull-request
#> #>
param ( param (
[Parameter(Mandatory)] [string] $RepositoryOwner, [Parameter(Mandatory)] [string] $RepositoryFullName,
[Parameter(Mandatory)] [string] $RepositoryName,
[Parameter(Mandatory)] [string] $AccessToken, [Parameter(Mandatory)] [string] $AccessToken,
[Parameter(Mandatory)] [string] $BranchName, [Parameter(Mandatory)] [string] $BranchName,
[Parameter(Mandatory)] [string] $CommitMessage, [Parameter(Mandatory)] [string] $CommitMessage,
@@ -46,11 +43,11 @@ function Update-PullRequest {
$updatedPullRequest = $GitHubApi.UpdatePullRequest($Title, $Body, $BranchName, $PullRequest.number) $updatedPullRequest = $GitHubApi.UpdatePullRequest($Title, $Body, $BranchName, $PullRequest.number)
if (($updatedPullRequest -eq $null) -or ($updatedPullRequest.html_url -eq $null)) { if (($null -eq $updatedPullRequest) -or ($null -eq $updatedPullRequest.html_url)) {
Write-Host "##vso[task.logissue type=error;] Unexpected error occurs while updating pull request." Write-Host "Unexpected error occurs while updating pull request."
exit 1 exit 1
} }
Write-host "##[section] Pull request updated: $($updatedPullRequest.html_url)" Write-host "Pull request updated: $($updatedPullRequest.html_url)"
} }
function Create-PullRequest { function Create-PullRequest {
@@ -67,12 +64,12 @@ function Create-PullRequest {
$createdPullRequest = $GitHubApi.CreateNewPullRequest($Title, $Body, $BranchName) $createdPullRequest = $GitHubApi.CreateNewPullRequest($Title, $Body, $BranchName)
if (($createdPullRequest -eq $null) -or ($createdPullRequest.html_url -eq $null)) { if (($null -eq $createdPullRequest) -or ($null -eq $createdPullRequest.html_url)) {
Write-Host "##vso[task.logissue type=error;] Unexpected error occurs while creating pull request." Write-Host "Unexpected error occurs while creating pull request."
exit 1 exit 1
} }
Write-host "##[section] Pull request created: $($createdPullRequest.html_url)" Write-host "Pull request created: $($createdPullRequest.html_url)"
} }
Write-Host "Configure local git preferences" Write-Host "Configure local git preferences"
@@ -87,8 +84,8 @@ Git-CommitAllChanges -Message $CommitMessage
Write-Host "Push branch: $BranchName" Write-Host "Push branch: $BranchName"
Git-PushBranch -Name $BranchName -Force $true Git-PushBranch -Name $BranchName -Force $true
$gitHubApi = Get-GitHubApi -AccountName $RepositoryOwner -ProjectName $RepositoryName -AccessToken $AccessToken $gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $AccessToken
$pullRequest = $gitHubApi.GetPullRequest($BranchName, $RepositoryOwner) $pullRequest = $gitHubApi.GetPullRequest($BranchName)
if ($pullRequest.Count -gt 0) { if ($pullRequest.Count -gt 0) {
Write-Host "Update pull request" Write-Host "Update pull request"

86
github/create-release.ps1 Normal file
View File

@@ -0,0 +1,86 @@
<#
.SYNOPSIS
Trigger runs on the workflow_dispatch event to create tool release
.PARAMETER RepositoryFullName
Required parameter. The owner and repository name. For example, 'actions/versions-package-tools'
.PARAMETER AccessToken
Required parameter. PAT Token to authorize
.PARAMETER ToolVersion
Required parameter. Version of tool
.PARAMETER TagName
Required parameter. The name of the release tag
.PARAMETER ReleaseBody
Required parameter. Text describing the contents of the release
.PARAMETER EventType
Required parameter. The name of the repository dispatch event
#>
param (
[Parameter(Mandatory)] [string] $RepositoryFullName,
[Parameter(Mandatory)] [string] $AccessToken,
[Parameter(Mandatory)] [string] $ToolVersion,
[Parameter(Mandatory)] [string] $TagName,
[Parameter(Mandatory)] [string] $ReleaseBody,
[Parameter(Mandatory)] [string] $EventType,
[UInt32] $RetryIntervalSec = 10,
[UInt32] $RetryCount = 5
)
Import-Module (Join-Path $PSScriptRoot "github-api.psm1")
function Create-Release {
param (
[Parameter(Mandatory)] [object] $GitHubApi,
[Parameter(Mandatory)] [string] $ToolVersion,
[Parameter(Mandatory)] [string] $TagName,
[Parameter(Mandatory)] [string] $ReleaseBody,
[Parameter(Mandatory)] [string] $EventType
)
$eventPayload = @{
ToolVersion = $ToolVersion
TagName = $TagName
ReleaseBody = $ReleaseBody
}
Write-Host "Create '$EventType' repository dispatch event"
$GitHubApi.CreateRepositoryDispatch($EventType, $eventPayload)
}
function Validate-ReleaseAvailability {
param (
[Parameter(Mandatory)] [object] $GitHubApi,
[Parameter(Mandatory)] [string] $TagName,
[Parameter(Mandatory)] [UInt32] $RetryIntervalSec,
[Parameter(Mandatory)] [UInt32] $RetryCount
)
do {
$createdRelease = $GitHubApi.GetReleases() | Where-Object { $_.tag_name -eq $TagName }
if ($createdRelease) {
Write-Host "Release was successfully created: $($createdRelease.html_url)"
return
}
$RetryCount--
Start-Sleep -Seconds $RetryIntervalSec
} while($RetryCount -gt 0)
Write-Host "Release was not created"
exit 1
}
$gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $AccessToken
Create-Release -GitHubApi $gitHubApi `
-ToolVersion $ToolVersion `
-TagName $TagName `
-ReleaseBody $ReleaseBody `
-EventType $EventType
Start-Sleep -s $RetryIntervalSec
Validate-ReleaseAvailability -GitHubApi $gitHubApi `
-TagName $TagName `
-RetryIntervalSec $RetryIntervalSec `
-RetryCount $RetryCount

View File

@@ -5,8 +5,8 @@ The module that contains a bunch of methods to interact with GitHub API V3
class GitHubApi class GitHubApi
{ {
[string] $BaseUrl [string] $BaseUrl
[string] $RepoOwner
[object] $AuthHeader [object] $AuthHeader
[string] $RepositoryOwner
GitHubApi( GitHubApi(
[string] $AccountName, [string] $AccountName,
@@ -15,6 +15,7 @@ class GitHubApi
) { ) {
$this.BaseUrl = $this.BuildBaseUrl($AccountName, $ProjectName) $this.BaseUrl = $this.BuildBaseUrl($AccountName, $ProjectName)
$this.AuthHeader = $this.BuildAuth($AccessToken) $this.AuthHeader = $this.BuildAuth($AccessToken)
$this.RepositoryOwner = $AccountName
} }
[object] hidden BuildAuth([string]$AccessToken) { [object] hidden BuildAuth([string]$AccessToken) {
@@ -43,9 +44,9 @@ class GitHubApi
return $this.InvokeRestMethod($url, 'Post', $null, $requestBody) return $this.InvokeRestMethod($url, 'Post', $null, $requestBody)
} }
[object] GetPullRequest([string]$BranchName, [string]$RepositoryOwner){ [object] GetPullRequest([string]$BranchName){
$url = "pulls" $url = "pulls"
return $this.InvokeRestMethod($url, 'GET', "head=${RepositoryOwner}:$BranchName&base=main", $null) return $this.InvokeRestMethod($url, 'GET', "head=$($this.RepositoryOwner):${BranchName}&base=main", $null)
} }
[object] UpdatePullRequest([string]$Title, [string]$Body, [string]$BranchName, [string]$PullRequestNumber){ [object] UpdatePullRequest([string]$Title, [string]$Body, [string]$BranchName, [string]$PullRequestNumber){
@@ -82,6 +83,39 @@ class GitHubApi
return $releases return $releases
} }
[void] CreateRepositoryDispatch([string]$EventType, [object]$EventPayload) {
$url = "dispatches"
$body = @{
event_type = $EventType
client_payload = $EventPayload
} | ConvertTo-Json
$this.InvokeRestMethod($url, 'POST', $null, $body)
}
[object] GetWorkflowRuns([string]$WorkflowFileName) {
$url = "actions/workflows/$WorkflowFileName/runs"
return $this.InvokeRestMethod($url, 'GET', $null, $null)
}
[object] GetWorkflowRunJobs([string]$WorkflowRunId) {
$url = "actions/runs/$WorkflowRunId/jobs"
return $this.InvokeRestMethod($url, 'GET', $null, $null)
}
[void] CreateWorkflowDispatch([string]$WorkflowFileName, [string]$Ref, [object]$Inputs) {
$url = "actions/workflows/${WorkflowFileName}/dispatches"
$body = @{ ref = $Ref }
if ($Inputs) {
$body.inputs = $Inputs
}
$jsonBody = $body | ConvertTo-Json
$this.InvokeRestMethod($url, 'POST', $null, $jsonBody)
}
[string] hidden BuildUrl([string]$Url, [string]$RequestParams) { [string] hidden BuildUrl([string]$Url, [string]$RequestParams) {
if ([string]::IsNullOrEmpty($RequestParams)) { if ([string]::IsNullOrEmpty($RequestParams)) {
return "$($this.BaseUrl)/$($Url)" return "$($this.BaseUrl)/$($Url)"
@@ -90,6 +124,11 @@ class GitHubApi
} }
} }
[void] CancelWorkflow([string]$WorkflowId) {
$url = "actions/runs/$WorkflowId/cancel"
$this.InvokeRestMethod($url, 'POST', $null, $null)
}
[object] hidden InvokeRestMethod( [object] hidden InvokeRestMethod(
[string] $Url, [string] $Url,
[string] $Method, [string] $Method,
@@ -117,10 +156,18 @@ class GitHubApi
function Get-GitHubApi { function Get-GitHubApi {
param ( param (
[string] $AccountName, [Parameter(ParameterSetName = 'RepositorySingle')]
[string] $ProjectName, [string] $RepositoryFullName,
[Parameter(ParameterSetName = 'RepositorySplitted')]
[string] $RepositoryOwner,
[Parameter(ParameterSetName = 'RepositorySplitted')]
[string] $RepositoryName,
[string] $AccessToken [string] $AccessToken
) )
return [GitHubApi]::New($AccountName, $ProjectName, $AccessToken) if ($PSCmdlet.ParameterSetName -eq "RepositorySingle") {
$RepositoryOwner, $RepositoryName = $RepositoryFullName.Split('/', 2)
}
return [GitHubApi]::New($RepositoryOwner, $RepositoryName, $AccessToken)
} }

91
github/run-ci-builds.ps1 Normal file
View File

@@ -0,0 +1,91 @@
<#
.SYNOPSIS
Trigger runs on the workflow_dispatch event to build and upload tool packages
.PARAMETER RepositoryFullName
Required parameter. The owner and repository name. For example, 'actions/versions-package-tools'
.PARAMETER AccessToken
Required parameter. PAT to authorize
.PARAMETER WorkflowFileName
Required parameter. The name of workflow file that will be triggered
.PARAMETER WorkflowDispatchRef
Required parameter. The reference of the workflow run. The reference can be a branch, tag, or a commit SHA.
.PARAMETER ToolVersions
Required parameter. List of tool versions to build and upload
.PARAMETER PublishReleases
Required parameter. Whether to publish releases, true or false
#>
param (
[Parameter(Mandatory)] [string] $RepositoryFullName,
[Parameter(Mandatory)] [string] $AccessToken,
[Parameter(Mandatory)] [string] $WorkflowFileName,
[Parameter(Mandatory)] [string] $WorkflowDispatchRef,
[Parameter(Mandatory)] [string] $ToolVersions,
[Parameter(Mandatory)] [string] $PublishReleases
)
Import-Module (Join-Path $PSScriptRoot "github-api.psm1")
function Get-WorkflowRunLink {
param(
[Parameter(Mandatory)] [object] $GitHubApi,
[Parameter(Mandatory)] [string] $WorkflowFileName,
[Parameter(Mandatory)] [string] $ToolVersion
)
$listWorkflowRuns = $GitHubApi.GetWorkflowRuns($WorkflowFileName).workflow_runs | Sort-Object -Property 'run_number' -Descending
foreach ($workflowRun in $listWorkflowRuns) {
$workflowRunJob = $gitHubApi.GetWorkflowRunJobs($workflowRun.id).jobs | Select-Object -First 1
if ($workflowRunJob.name -match $ToolVersion) {
return $workflowRun.html_url
}
}
return $null
}
function Queue-Builds {
param (
[Parameter(Mandatory)] [object] $GitHubApi,
[Parameter(Mandatory)] [string] $ToolVersions,
[Parameter(Mandatory)] [string] $WorkflowFileName,
[Parameter(Mandatory)] [string] $WorkflowDispatchRef,
[Parameter(Mandatory)] [string] $PublishReleases
)
$inputs = @{
PUBLISH_RELEASES = $PublishReleases
}
$ToolVersions.Split(',') | ForEach-Object {
$version = $_.Trim()
$inputs.VERSION = $version
Write-Host "Queue build for $version..."
$GitHubApi.CreateWorkflowDispatch($WorkflowFileName, $WorkflowDispatchRef, $inputs)
Start-Sleep -s 10
$workflowRunLink = Get-WorkflowRunLink -GitHubApi $GitHubApi `
-WorkflowFileName $WorkflowFileName `
-ToolVersion $version
if (-not $workflowRunLink) {
Write-Host "Could not find build for $version..."
exit 1
}
Write-Host "Link to the build: $workflowRunLink"
}
}
$gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $AccessToken
Write-Host "Versions to build: $ToolVersions"
Queue-Builds -GitHubApi $gitHubApi `
-ToolVersions $ToolVersions `
-WorkflowFileName $WorkflowFileName `
-WorkflowDispatchRef $WorkflowDispatchRef `
-PublishReleases $PublishReleases

View File

@@ -1,13 +1,10 @@
<# <#
.SYNOPSIS .SYNOPSIS
Generate versions manifest based on repository releases Generate versions manifest based on repository releases
.DESCRIPTION .DESCRIPTION
Versions manifest is needed to find the latest assets for particular version of tool Versions manifest is needed to find the latest assets for particular version of tool
.PARAMETER GitHubRepositoryOwner .PARAMETER RepositoryFullName
Required parameter. The organization which tool repository belongs Required parameter. The owner and repository name. For example, 'actions/versions-package-tools'
.PARAMETER GitHubRepositoryName
Required parameter. The name of tool repository
.PARAMETER GitHubAccessToken .PARAMETER GitHubAccessToken
Required parameter. PAT Token to overcome GitHub API Rate limit Required parameter. PAT Token to overcome GitHub API Rate limit
.PARAMETER OutputFile .PARAMETER OutputFile
@@ -17,8 +14,7 @@ Path to the json file with parsing configuration
#> #>
param ( param (
[Parameter(Mandatory)] [string] $GitHubRepositoryOwner, [Parameter(Mandatory)] [string] $RepositoryFullName,
[Parameter(Mandatory)] [string] $GitHubRepositoryName,
[Parameter(Mandatory)] [string] $GitHubAccessToken, [Parameter(Mandatory)] [string] $GitHubAccessToken,
[Parameter(Mandatory)] [string] $OutputFile, [Parameter(Mandatory)] [string] $OutputFile,
[Parameter(Mandatory)] [string] $ConfigurationFile [Parameter(Mandatory)] [string] $ConfigurationFile
@@ -29,7 +25,7 @@ Import-Module (Join-Path $PSScriptRoot "manifest-utils.psm1") -Force
$configuration = Read-ConfigurationFile -Filepath $ConfigurationFile $configuration = Read-ConfigurationFile -Filepath $ConfigurationFile
$gitHubApi = Get-GitHubApi -AccountName $GitHubRepositoryOwner -ProjectName $GitHubRepositoryName -AccessToken $GitHubAccessToken $gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $GitHubAccessToken
$releases = $gitHubApi.GetReleases() $releases = $gitHubApi.GetReleases()
$versionIndex = Build-VersionsManifest -Releases $releases -Configuration $configuration $versionIndex = Build-VersionsManifest -Releases $releases -Configuration $configuration
$versionIndex | ConvertTo-Json -Depth 5 | Out-File $OutputFile -Encoding UTF8NoBOM -Force $versionIndex | ConvertTo-Json -Depth 5 | Out-File $OutputFile -Encoding UTF8NoBOM -Force

View File

@@ -77,6 +77,7 @@ Describe "Build-VersionsManifest" {
$assets = @( $assets = @(
@{ name = "python-3.8.3-linux-16.04-x64.tar.gz"; browser_download_url = "fake_url"; } @{ name = "python-3.8.3-linux-16.04-x64.tar.gz"; browser_download_url = "fake_url"; }
@{ name = "python-3.8.3-linux-18.04-x64.tar.gz"; browser_download_url = "fake_url"; } @{ name = "python-3.8.3-linux-18.04-x64.tar.gz"; browser_download_url = "fake_url"; }
@{ name = "hashes.sha256"; browser_download_url = "fake_url"; }
) )
$configuration = @{ $configuration = @{
regex = "python-\d+\.\d+\.\d+-(\w+)-([\w\.]+)?-?(x\d+)"; regex = "python-\d+\.\d+\.\d+-(\w+)-([\w\.]+)?-?(x\d+)";
@@ -126,7 +127,7 @@ Describe "Build-VersionsManifest" {
[PSCustomObject]@{ version = "3.8.3"; stable = $true; release_url = "fake_html_url"; files = $expectedManifestFiles } [PSCustomObject]@{ version = "3.8.3"; stable = $true; release_url = "fake_html_url"; files = $expectedManifestFiles }
) )
[array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration [array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration
Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest
} }
It "take latest published release for each version" { It "take latest published release for each version" {
@@ -141,4 +142,74 @@ Describe "Build-VersionsManifest" {
[array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration [array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration
Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest
} }
It "build correct manifest if release includes one asset" {
$asset = @(
@{ name = "python-3.8.3-linux-16.04-x64.tar.gz"; browser_download_url = "fake_url"; }
)
$expectedManifestFile = @(
[PSCustomObject]@{ filename = "python-3.8.3-linux-16.04-x64.tar.gz"; arch = "x64"; platform = "linux"; platform_version = "16.04"; download_url = "fake_url" }
)
$releases = @(
@{ name = "3.8.3"; draft = $false; prerelease = $false; html_url = "fake_html_url"; published_at = "2020-05-06T11:43:38Z"; assets = $asset },
@{ name = "3.8.1"; draft = $false; prerelease = $false; html_url = "fake_html_url"; published_at = "2020-05-14T09:54:06Z"; assets = $assets }
)
$expectedManifest = @(
[PSCustomObject]@{ version = "3.8.3"; stable = $true; release_url = "fake_html_url"; files = $expectedManifestFile },
[PSCustomObject]@{ version = "3.8.1"; stable = $true; release_url = "fake_html_url"; files = $expectedManifestFiles }
)
[array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration
Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest
}
It "set correct lts value for versions" {
$releases = @(
@{ name = "14.2.1"; draft = false; prerelease = $false; html_url = "fake_html_url"; published_at = "2020-05-14T09:54:06Z"; assets = $assets },
@{ name = "12.0.1"; draft = $false; prerelease = false; html_url = "fake_html_url"; published_at = "2020-05-06T11:45:36Z"; assets = $assets },
@{ name = "16.2.2"; draft = $false; prerelease = $false; html_url = "fake_html_url"; published_at = "2020-05-06T11:43:38Z"; assets = $assets }
)
$configuration = @{
regex = "python-\d+\.\d+\.\d+-(\w+)-([\w\.]+)?-?(x\d+)";
groups = [PSCustomObject]@{ platform = 1; platform_version = 2; arch = "x64"; }
lts_rule_expression = "@(@{ Name = '14'; Value = 'Fermium' }, @{ Name = '12'; Value = 'Erbium' })"
}
$expectedManifest = @(
[PSCustomObject]@{ version = "16.2.2"; stable = $true; release_url = "fake_html_url"; files = $expectedManifestFiles },
[PSCustomObject]@{ version = "14.2.1"; stable = $true; lts = "Fermium"; release_url = "fake_html_url"; files = $expectedManifestFiles },
[PSCustomObject]@{ version = "12.0.1"; stable = $true; lts = "Erbium"; release_url = "fake_html_url"; files = $expectedManifestFiles }
)
[array]$actualManifest = Build-VersionsManifest -Releases $releases -Configuration $configuration
Assert-Equivalent -Actual $actualManifest -Expected $expectedManifest
}
}
Describe "Get-VersionLtsStatus" {
$ltsRules = @(
@{ Name = "14"; Value = "Fermium" },
@{ Name = "12"; Value = "Erbium" },
@{ Name = "10"; Value = $true },
@{ Name = "8.3"; Value = "LTS 8.3" }
)
It "lts label is matched" {
Get-VersionLtsStatus -Version "14.2.2" -LtsRules $ltsRules | Should -Be "Fermium"
Get-VersionLtsStatus -Version "12.3.1" -LtsRules $ltsRules | Should -Be "Erbium"
Get-VersionLtsStatus -Version "10.8.1" -LtsRules $ltsRules | Should -Be $true
Get-VersionLtsStatus -Version "8.3.2" -LtsRules $ltsRules | Should -Be "LTS 8.3"
Get-VersionLtsStatus -Version "14" -LtsRules $ltsRules | Should -Be "Fermium"
}
It "lts label is not matched" {
Get-VersionLtsStatus -Version "9.1" -LtsRules $ltsRules | Should -Be $null
Get-VersionLtsStatus -Version "13.8" -LtsRules $ltsRules | Should -Be $null
Get-VersionLtsStatus -Version "5" -LtsRules $ltsRules | Should -Be $null
Get-VersionLtsStatus -Version "8.4" -LtsRules $ltsRules | Should -Be $null
Get-VersionLtsStatus -Version "142.5.1" -LtsRules $ltsRules | Should -Be $null
}
It "no rules" {
Get-VersionLtsStatus -Version "14.2.2" | Should -Be $null
Get-VersionLtsStatus -Version "12.3.1" -LtsRules $null | Should -Be $null
}
} }

View File

@@ -50,6 +50,7 @@ function Build-VersionsManifest {
) )
$Releases = $Releases | Sort-Object -Property "published_at" -Descending $Releases = $Releases | Sort-Object -Property "published_at" -Descending
$ltsRules = Get-LtsRules -Configuration $Configuration
$versionsHash = @{} $versionsHash = @{}
foreach ($release in $Releases) { foreach ($release in $Releases) {
@@ -64,15 +65,49 @@ function Build-VersionsManifest {
continue continue
} }
$ltsStatus = Get-VersionLtsStatus -Version $versionKey -LtsRules $ltsRules
$stable = $version.PreReleaseLabel ? $false : $true $stable = $version.PreReleaseLabel ? $false : $true
$versionsHash.Add($versionKey, [PSCustomObject]@{ [array]$releaseAssets = $release.assets | Where { $_.Name -ne "hashes.sha256" } | ForEach-Object { New-AssetItem -ReleaseAsset $_ -Configuration $Configuration }
version = $versionKey
stable = $stable $versionHash = [PSCustomObject]@{}
release_url = $release.html_url $versionHash | Add-Member -Name "version" -Value $versionKey -MemberType NoteProperty
files = $release.assets | ForEach-Object { New-AssetItem -ReleaseAsset $_ -Configuration $Configuration } $versionHash | Add-Member -Name "stable" -Value $stable -MemberType NoteProperty
}) if ($ltsStatus) {
$versionHash | Add-Member -Name "lts" -Value $ltsStatus -MemberType NoteProperty
}
$versionHash | Add-Member -Name "release_url" -Value $release.html_url -MemberType NoteProperty
$versionHash | Add-Member -Name "files" -Value $releaseAssets -MemberType NoteProperty
$versionsHash.Add($versionKey, $versionHash)
} }
# Sort versions by descending # Sort versions by descending
return $versionsHash.Values | Sort-Object -Property @{ Expression = { [Semver]$_.version }; Descending = $true } return $versionsHash.Values | Sort-Object -Property @{ Expression = { [Semver]$_.version }; Descending = $true }
} }
function Get-LtsRules {
param (
[Parameter(Mandatory)][object]$Configuration
)
$ruleExpression = $Configuration."lts_rule_expression"
if ($ruleExpression) {
Invoke-Expression $ruleExpression
} else {
@()
}
}
function Get-VersionLtsStatus {
param (
[Parameter(Mandatory)][string]$Version,
[array]$LtsRules
)
foreach ($ltsRule in $LtsRules) {
if (($Version -eq $ltsRule.Name) -or ($Version.StartsWith("$($ltsRule.Name)."))) {
return $ltsRule.Value
}
}
return $null
}

View File

@@ -1,30 +1,29 @@
param ( param (
[Parameter(Mandatory)][string] $ManifestUrl, [Parameter(Mandatory)][string] $ManifestPath
[string] $AccessToken
) )
$authorizationHeaderValue = "Basic $AccessToken" $Global:validationFailed = $false
$webRequestHeaders = @{}
if ($AccessToken) {
$webRequestHeaders.Add("Authorization", $authorizationHeaderValue)
}
function Publish-Error { function Publish-Error {
param( param(
[string] $ErrorDescription, [string] $ErrorDescription,
[object] $Exception [object] $Exception
) )
Write-Host "##vso[task.logissue type=error]ERROR: $ErrorDescription."
Write-Host "##vso[task.logissue type=error] $Exception" Write-Output "::error ::$ErrorDescription"
Write-Host "##vso[task.complete result=Failed;]" if (-not [string]::IsNullOrEmpty($Exception))
{
Write-Output "Exception: $Exception"
}
$Global:validationFailed = $true
} }
function Test-DownloadUrl { function Test-DownloadUrl {
param([string] $DownloadUrl) param(
[string] $DownloadUrl
)
$request = [System.Net.WebRequest]::Create($DownloadUrl) $request = [System.Net.WebRequest]::Create($DownloadUrl)
if ($AccessToken) {
$request.Headers.Add("Authorization", $authorizationHeaderValue)
}
try { try {
$response = $request.GetResponse() $response = $request.GetResponse()
return ([int]$response.StatusCode -eq 200) return ([int]$response.StatusCode -eq 200)
@@ -33,19 +32,16 @@ function Test-DownloadUrl {
} }
} }
Write-Host "Downloading manifest json from '$ManifestUrl'..." if (-not (Test-Path $ManifestPath)) {
try { Publish-Error "Unable to find manifest json file at '$ManifestPath'"
$manifestResponse = Invoke-WebRequest -Method Get -Uri $ManifestUrl -Headers $webRequestHeaders
} catch {
Publish-Error "Unable to download manifest json from '$ManifestUrl'" $_
exit 1 exit 1
} }
Write-Host "Parsing manifest json content from '$ManifestUrl'..." Write-Host "Parsing manifest json content from '$ManifestPath'..."
try { try {
$manifestJson = $manifestResponse.Content | ConvertFrom-Json $manifestJson = Get-Content $ManifestPath | ConvertFrom-Json
} catch { } catch {
Publish-Error "Unable to parse manifest json content '$ManifestUrl'" $_ Publish-Error "Unable to parse manifest json content '$ManifestPath'" $_
exit 1 exit 1
} }
@@ -61,3 +57,7 @@ $manifestJson | ForEach-Object {
} }
} }
} }
if ($Global:validationFailed) {
exit 1
}

View File

@@ -4,30 +4,52 @@ Pester extension that allows to run command and validate exit code
.EXAMPLE .EXAMPLE
"python file.py" | Should -ReturnZeroExitCode "python file.py" | Should -ReturnZeroExitCode
#> #>
function Get-CommandResult {
Param (
[Parameter(Mandatory=$true)]
[string] $Command,
[switch] $Multiline
)
# CMD and bash trick to suppress and show error output because some commands write to stderr (for example, "python --version")
If ($IsWindows) {
$stdout = & $env:comspec /c "$Command 2>&1"
} else {
$stdout = & bash -c "$Command 2>&1"
}
$exitCode = $LASTEXITCODE
return @{
Output = If ($Multiline -eq $true) { $stdout } else { [string]$stdout }
ExitCode = $exitCode
}
}
function ShouldReturnZeroExitCode { function ShouldReturnZeroExitCode {
Param( Param(
[Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $ActualValue,
[String]$ActualValue, [switch] $Negate,
[switch]$Negate [string] $Because # This parameter is unused by we need it to match Pester asserts signature
) )
Write-Host "Run command '${ActualValue}'" $result = Get-CommandResult $ActualValue
Invoke-Expression -Command $ActualValue | ForEach-Object { Write-Host $_ }
$actualExitCode = $LASTEXITCODE
[bool]$succeeded = $actualExitCode -eq 0 [bool]$succeeded = $result.ExitCode -eq 0
if ($Negate) { $succeeded = -not $succeeded } if ($Negate) { $succeeded = -not $succeeded }
if (-not $succeeded) if (-not $succeeded)
{ {
$failureMessage = "Command '${ActualValue}' has finished with exit code ${actualExitCode}" $commandOutputIndent = " " * 4
$commandOutput = ($result.Output | ForEach-Object { "${commandOutputIndent}${_}" }) -join "`n"
$failureMessage = "Command '${ActualValue}' has finished with exit code ${actualExitCode}`n${commandOutput}"
} }
return New-Object PSObject -Property @{ return [PSCustomObject] @{
Succeeded = $succeeded Succeeded = $succeeded
FailureMessage = $failureMessage FailureMessage = $failureMessage
} }
} }
Add-AssertionOperator -Name ReturnZeroExitCode ` if (Get-Command -Name Add-AssertionOperator -ErrorAction SilentlyContinue) {
-Test $function:ShouldReturnZeroExitCode Add-AssertionOperator -Name ReturnZeroExitCode -InternalName ShouldReturnZeroExitCode -Test ${function:ShouldReturnZeroExitCode}
}