Added SetupGitHubRelease Task
This commit is contained in:
680
task/SetupGitHubRelease/package-lock.json
generated
Normal file
680
task/SetupGitHubRelease/package-lock.json
generated
Normal file
@@ -0,0 +1,680 @@
|
||||
{
|
||||
"name": "setup-github-release-task",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "setup-github-release-task",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"azure-pipelines-task-lib": "^5.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.30",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.walk": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
|
||||
"integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
|
||||
"integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/azure-pipelines-task-lib": {
|
||||
"version": "5.2.6",
|
||||
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-5.2.6.tgz",
|
||||
"integrity": "sha512-YWEJFAY+Imk5nWwPd5ao6h/J8BgW2Dtzt+M5QiUWDV5cB10n4zywQ5Dulj2OcO1B9tGfdV5KDKVnQRKfJ72YmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.5.10",
|
||||
"minimatch": "3.0.5",
|
||||
"nodejs-file-downloader": "^4.11.1",
|
||||
"q": "^1.5.1",
|
||||
"semver": "^5.7.2",
|
||||
"shelljs": "^0.10.0",
|
||||
"uuid": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.3",
|
||||
"get-stream": "^6.0.0",
|
||||
"human-signals": "^2.1.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^4.0.1",
|
||||
"onetime": "^5.1.2",
|
||||
"signal-exit": "^3.0.3",
|
||||
"strip-final-newline": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
|
||||
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
|
||||
"integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nodejs-file-downloader": {
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/nodejs-file-downloader/-/nodejs-file-downloader-4.13.0.tgz",
|
||||
"integrity": "sha512-nI2fKnmJWWFZF6SgMPe1iBodKhfpztLKJTtCtNYGhm/9QXmWa/Pk9Sv00qHgzEvNLe1x7hjGDRor7gcm/ChaIQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"sanitize-filename": "^1.6.3"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/onetime": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
"integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
|
||||
"deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.0",
|
||||
"teleport": ">=0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
|
||||
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/sanitize-filename": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
|
||||
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
|
||||
"license": "WTFPL OR ISC",
|
||||
"dependencies": {
|
||||
"truncate-utf8-bytes": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shelljs": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz",
|
||||
"integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"execa": "^5.1.1",
|
||||
"fast-glob": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/strip-final-newline": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/truncate-utf8-bytes": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
||||
"integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==",
|
||||
"license": "WTFPL",
|
||||
"dependencies": {
|
||||
"utf8-byte-length": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/utf8-byte-length": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
||||
"integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==",
|
||||
"license": "(WTFPL OR MIT)"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
task/SetupGitHubRelease/package.json
Normal file
23
task/SetupGitHubRelease/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "setup-github-release-task",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"author": "Slawomir Koszewski",
|
||||
"license": "MIT",
|
||||
"description": "Azure DevOps task to download and install the latest release asset from GitHub.",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"azure-pipelines-task-lib": "^5.2.6"
|
||||
},
|
||||
"overrides": {
|
||||
"minimatch": "3.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.30",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
430
task/SetupGitHubRelease/src/index.ts
Normal file
430
task/SetupGitHubRelease/src/index.ts
Normal file
@@ -0,0 +1,430 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as fsp from 'node:fs/promises';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
|
||||
type ReleaseAsset = {
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
};
|
||||
|
||||
type ReleaseInfo = {
|
||||
tag_name: string;
|
||||
assets: ReleaseAsset[];
|
||||
};
|
||||
|
||||
type PlatformInfo = {
|
||||
system: string;
|
||||
arch: string;
|
||||
systemPattern: string;
|
||||
archPattern: string;
|
||||
};
|
||||
|
||||
type MatchOptions = {
|
||||
fileName?: string;
|
||||
fileType?: string;
|
||||
};
|
||||
|
||||
const systemPatterns: Record<string, string> = {
|
||||
linux: 'linux',
|
||||
darwin: '(darwin|macos|mac|osx)',
|
||||
win32: '(windows|win)'
|
||||
};
|
||||
|
||||
const archPatterns: Record<string, string> = {
|
||||
x64: '(x86_64|x64|amd64)',
|
||||
arm64: '(aarch64|arm64)'
|
||||
};
|
||||
|
||||
function getPlatformInfo(): PlatformInfo {
|
||||
const system = os.platform();
|
||||
const arch = os.arch();
|
||||
|
||||
return {
|
||||
system,
|
||||
arch,
|
||||
systemPattern: systemPatterns[system] || system,
|
||||
archPattern: archPatterns[arch] || arch
|
||||
};
|
||||
}
|
||||
|
||||
function getExtensionPattern(fileType: string): string {
|
||||
if (fileType === 'archive') {
|
||||
return '\\.(zip|tar\\.gz|tar|tgz|7z)';
|
||||
}
|
||||
|
||||
if (fileType === 'package') {
|
||||
return '\\.(deb|rpm|pkg)';
|
||||
}
|
||||
|
||||
return fileType;
|
||||
}
|
||||
|
||||
function getMatchingAsset(assets: ReleaseAsset[], platform: PlatformInfo, options: MatchOptions): ReleaseAsset {
|
||||
const fileName = options.fileName;
|
||||
const extPattern = getExtensionPattern(options.fileType || 'archive');
|
||||
|
||||
if (!fileName) {
|
||||
const pattern = `${platform.systemPattern}[_-]${platform.archPattern}.*${extPattern}$`;
|
||||
const regex = new RegExp(pattern, 'i');
|
||||
const matches = assets.filter((asset) => regex.test(asset.name));
|
||||
if (matches.length === 0) {
|
||||
throw new Error(`No assets matched the default criteria: ${pattern}`);
|
||||
}
|
||||
|
||||
if (matches.length > 1) {
|
||||
throw new Error(`Multiple assets matched the default criteria: ${matches.map((asset) => asset.name).join(', ')}`);
|
||||
}
|
||||
|
||||
return matches[0];
|
||||
}
|
||||
|
||||
if (fileName.startsWith('~')) {
|
||||
let pattern = fileName.substring(1);
|
||||
const hasSystem = pattern.includes('{{SYSTEM}}');
|
||||
const hasArch = pattern.includes('{{ARCH}}');
|
||||
const hasExt = pattern.includes('{{EXT_PATTERN}}');
|
||||
const hasEnd = pattern.endsWith('$');
|
||||
|
||||
if (!hasSystem && !hasArch && !hasExt && !hasEnd) {
|
||||
pattern += '.*{{SYSTEM}}[_-]{{ARCH}}.*{{EXT_PATTERN}}$';
|
||||
} else if (hasSystem && hasArch && !hasExt && !hasEnd) {
|
||||
pattern += '.*{{EXT_PATTERN}}$';
|
||||
}
|
||||
|
||||
const finalPattern = pattern
|
||||
.replace(/{{SYSTEM}}/g, platform.systemPattern)
|
||||
.replace(/{{ARCH}}/g, platform.archPattern)
|
||||
.replace(/{{EXT_PATTERN}}/g, extPattern);
|
||||
|
||||
const regex = new RegExp(finalPattern, 'i');
|
||||
const matches = assets.filter((asset) => regex.test(asset.name));
|
||||
if (matches.length === 0) {
|
||||
throw new Error(`No assets matched the regex: ${finalPattern}`);
|
||||
}
|
||||
|
||||
if (matches.length > 1) {
|
||||
throw new Error(`Multiple assets matched the criteria: ${matches.map((asset) => asset.name).join(', ')}`);
|
||||
}
|
||||
|
||||
return matches[0];
|
||||
}
|
||||
|
||||
const exact = assets.find((asset) => asset.name === fileName);
|
||||
if (!exact) {
|
||||
throw new Error(`No asset found matching the exact name: ${fileName}`);
|
||||
}
|
||||
|
||||
return exact;
|
||||
}
|
||||
|
||||
async function fetchLatestRelease(repository: string, token?: string): Promise<ReleaseInfo> {
|
||||
const url = `https://api.github.com/repos/${repository}/releases/latest`;
|
||||
const headers: Record<string, string> = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'setup-github-release-ado-task'
|
||||
};
|
||||
|
||||
if (token) {
|
||||
headers.Authorization = `token ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url, { headers });
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`Failed to fetch latest release for ${repository}: ${response.status} ${response.statusText}. ${body}`);
|
||||
}
|
||||
|
||||
return (await response.json()) as ReleaseInfo;
|
||||
}
|
||||
|
||||
async function downloadAsset(url: string, destinationPath: string, token?: string): Promise<void> {
|
||||
const headers: Record<string, string> = {
|
||||
'User-Agent': 'setup-github-release-ado-task'
|
||||
};
|
||||
|
||||
if (token) {
|
||||
headers.Authorization = `token ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url, { headers });
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`Failed to download asset from ${url}: ${response.status} ${response.statusText}. ${body}`);
|
||||
}
|
||||
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
await fsp.writeFile(destinationPath, Buffer.from(arrayBuffer));
|
||||
}
|
||||
|
||||
async function extractAsset(filePath: string, destinationDirectory: string): Promise<void> {
|
||||
const lowerName = path.basename(filePath).toLowerCase();
|
||||
|
||||
await fsp.mkdir(destinationDirectory, { recursive: true });
|
||||
|
||||
if (lowerName.endsWith('.tar.gz') || lowerName.endsWith('.tgz') || lowerName.endsWith('.tar')) {
|
||||
const result = spawnSync('tar', ['-xf', filePath, '-C', destinationDirectory]);
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`tar failed with status ${result.status}: ${result.stderr.toString()}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (lowerName.endsWith('.zip')) {
|
||||
if (process.platform === 'win32') {
|
||||
const tarResult = spawnSync('tar', ['-xf', filePath, '-C', destinationDirectory]);
|
||||
if (tarResult.status === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const escapedFilePath = filePath.replace(/'/g, "''");
|
||||
const escapedDestinationDirectory = destinationDirectory.replace(/'/g, "''");
|
||||
const command = `Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFilePath}', '${escapedDestinationDirectory}')`;
|
||||
|
||||
for (const shell of ['pwsh', 'powershell']) {
|
||||
const result = spawnSync(shell, ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', command]);
|
||||
if (result.status === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('ZIP extraction failed on Windows.');
|
||||
}
|
||||
|
||||
const unzipResult = spawnSync('unzip', ['-q', filePath, '-d', destinationDirectory]);
|
||||
if (unzipResult.status !== 0) {
|
||||
throw new Error(`unzip failed with status ${unzipResult.status}: ${unzipResult.stderr.toString()}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (lowerName.endsWith('.7z')) {
|
||||
const sevenZipResult = spawnSync('7z', ['x', filePath, `-o${destinationDirectory}`, '-y']);
|
||||
if (sevenZipResult.status !== 0) {
|
||||
throw new Error(`7z failed with status ${sevenZipResult.status}: ${sevenZipResult.stderr.toString()}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (lowerName.endsWith('.pkg') || lowerName.endsWith('.xar')) {
|
||||
const xarResult = spawnSync('xar', ['-xf', filePath], { cwd: destinationDirectory });
|
||||
if (xarResult.status !== 0) {
|
||||
throw new Error(`xar failed with status ${xarResult.status}: ${xarResult.stderr.toString()}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const destinationPath = path.join(destinationDirectory, path.basename(filePath));
|
||||
await fsp.copyFile(filePath, destinationPath);
|
||||
}
|
||||
|
||||
function findBinary(directory: string, pattern: string | RegExp, debug: boolean): string | undefined {
|
||||
const items = fs.readdirSync(directory);
|
||||
|
||||
if (debug) {
|
||||
tl.debug(`Searching for binary in ${directory}`);
|
||||
for (const item of items) {
|
||||
tl.debug(`- ${item}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(directory, item);
|
||||
const stat = fs.statSync(fullPath);
|
||||
if (stat.isDirectory()) {
|
||||
const nested = findBinary(fullPath, pattern, debug);
|
||||
if (nested) {
|
||||
return nested;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let match = false;
|
||||
if (pattern instanceof RegExp) {
|
||||
match = pattern.test(item);
|
||||
} else {
|
||||
match = item === pattern;
|
||||
if (!match && process.platform === 'win32' && !pattern.toLowerCase().endsWith('.exe')) {
|
||||
match = item.toLowerCase() === `${pattern.toLowerCase()}.exe`;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function copyDirectory(sourceDirectory: string, destinationDirectory: string): Promise<void> {
|
||||
await fsp.mkdir(destinationDirectory, { recursive: true });
|
||||
const entries = await fsp.readdir(sourceDirectory, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const sourcePath = path.join(sourceDirectory, entry.name);
|
||||
const destinationPath = path.join(destinationDirectory, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
await copyDirectory(sourcePath, destinationPath);
|
||||
} else if (entry.isSymbolicLink()) {
|
||||
const linkTarget = await fsp.readlink(sourcePath);
|
||||
await fsp.symlink(linkTarget, destinationPath);
|
||||
} else {
|
||||
await fsp.copyFile(sourcePath, destinationPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getToolsRoot(): string {
|
||||
const toolsDirectory = tl.getVariable('Agent.ToolsDirectory');
|
||||
if (toolsDirectory !== undefined) {
|
||||
return toolsDirectory;
|
||||
}
|
||||
|
||||
return path.join(os.homedir(), '.ado-sk-tools');
|
||||
}
|
||||
|
||||
async function findAnyCachedVersion(toolName: string, arch: string): Promise<{ version: string; toolDirectory: string } | undefined> {
|
||||
const archRoot = path.join(getToolsRoot(), toolName);
|
||||
if (!fs.existsSync(archRoot)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const entries = await fsp.readdir(archRoot, { withFileTypes: true });
|
||||
const versions = entries
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => entry.name)
|
||||
.sort();
|
||||
|
||||
for (let index = versions.length - 1; index >= 0; index -= 1) {
|
||||
const version = versions[index];
|
||||
const candidate = path.join(archRoot, version, arch);
|
||||
if (fs.existsSync(candidate)) {
|
||||
return {
|
||||
version,
|
||||
toolDirectory: candidate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getSpecificCacheDirectory(toolName: string, version: string, arch: string): string {
|
||||
return path.join(getToolsRoot(), toolName, version, arch);
|
||||
}
|
||||
|
||||
async function cacheTool(sourceDirectory: string, toolName: string, version: string, arch: string): Promise<string> {
|
||||
const destinationDirectory = getSpecificCacheDirectory(toolName, version, arch);
|
||||
await fsp.rm(destinationDirectory, { recursive: true, force: true });
|
||||
await copyDirectory(sourceDirectory, destinationDirectory);
|
||||
return destinationDirectory;
|
||||
}
|
||||
|
||||
function setExecutable(filePath: string): void {
|
||||
if (process.platform !== 'win32') {
|
||||
fs.chmodSync(filePath, 0o755);
|
||||
}
|
||||
}
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const repository = tl.getInputRequired('repository');
|
||||
const fileNameInput = tl.getInput('fileName', false) || '';
|
||||
const binaryInput = tl.getInput('binaryName', false) || '';
|
||||
const fileType = tl.getInput('fileType', false) || 'archive';
|
||||
const updateCache = (tl.getInput('updateCache', false) || 'false').toLowerCase();
|
||||
const debug = tl.getBoolInput('debug', false);
|
||||
const token = tl.getInput('token', false) || process.env.GITHUB_TOKEN;
|
||||
|
||||
if (!/^[^/\s]+\/[^/\s]+$/.test(repository)) {
|
||||
throw new Error('Input repository must be in owner/repo format.');
|
||||
}
|
||||
|
||||
if (!['false', 'true', 'always'].includes(updateCache)) {
|
||||
throw new Error('Input updateCache must be one of: false, true, always.');
|
||||
}
|
||||
|
||||
const platformInfo = getPlatformInfo();
|
||||
const toolName = repository.split('/').pop() || repository;
|
||||
|
||||
if (updateCache === 'false') {
|
||||
const cached = await findAnyCachedVersion(toolName, platformInfo.arch);
|
||||
if (cached) {
|
||||
tl.debug(`Using cached ${toolName} version ${cached.version}`);
|
||||
tl.prependPath(cached.toolDirectory);
|
||||
tl.setResult(tl.TaskResult.Succeeded, `Using cached ${toolName} version ${cached.version}.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tl.debug(`Fetching latest release for ${repository}`);
|
||||
const release = await fetchLatestRelease(repository, token);
|
||||
const asset = getMatchingAsset(release.assets, platformInfo, {
|
||||
fileName: fileNameInput,
|
||||
fileType
|
||||
});
|
||||
|
||||
const version = release.tag_name.replace(/^v/, '');
|
||||
const binaryName = binaryInput || toolName;
|
||||
|
||||
if (updateCache !== 'always') {
|
||||
const cachedDirectory = getSpecificCacheDirectory(toolName, version, platformInfo.arch);
|
||||
if (fs.existsSync(cachedDirectory)) {
|
||||
tl.debug(`Using cached ${toolName} version ${version}`);
|
||||
tl.prependPath(cachedDirectory);
|
||||
tl.setResult(tl.TaskResult.Succeeded, `Using cached ${toolName} version ${version}.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const tempRoot = await fsp.mkdtemp(path.join(os.tmpdir(), 'setup-github-release-'));
|
||||
const downloadPath = path.join(tempRoot, asset.name);
|
||||
|
||||
tl.debug(`Downloading asset ${asset.name}`);
|
||||
await downloadAsset(asset.browser_download_url, downloadPath, token);
|
||||
|
||||
let extractionRoot = path.join(tempRoot, 'extract');
|
||||
const lowerName = asset.name.toLowerCase();
|
||||
|
||||
if (
|
||||
/\.(tar\.gz|tar|tgz)$/i.test(lowerName) ||
|
||||
/\.zip$/i.test(lowerName) ||
|
||||
/\.7z$/i.test(lowerName) ||
|
||||
/\.(xar|pkg)$/i.test(lowerName)
|
||||
) {
|
||||
await extractAsset(downloadPath, extractionRoot);
|
||||
} else {
|
||||
extractionRoot = path.join(tempRoot, 'bin');
|
||||
await fsp.mkdir(extractionRoot, { recursive: true });
|
||||
const destinationPath = path.join(extractionRoot, asset.name);
|
||||
await fsp.rename(downloadPath, destinationPath);
|
||||
setExecutable(destinationPath);
|
||||
}
|
||||
|
||||
const binaryPattern = binaryName.startsWith('~')
|
||||
? new RegExp(binaryName.substring(1), 'i')
|
||||
: binaryName;
|
||||
|
||||
const binaryPath = findBinary(extractionRoot, binaryPattern, debug);
|
||||
if (!binaryPath) {
|
||||
throw new Error(`Could not find binary ${binaryName} in extracted asset.`);
|
||||
}
|
||||
|
||||
setExecutable(binaryPath);
|
||||
|
||||
const binaryDirectory = path.dirname(binaryPath);
|
||||
const cachedDirectory = await cacheTool(binaryDirectory, toolName, version, platformInfo.arch);
|
||||
|
||||
tl.prependPath(cachedDirectory);
|
||||
tl.setResult(tl.TaskResult.Succeeded, `Installed ${toolName} ${version} from ${repository}.`);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
tl.setResult(tl.TaskResult.Failed, message);
|
||||
}
|
||||
}
|
||||
|
||||
void run();
|
||||
85
task/SetupGitHubRelease/task.json
Normal file
85
task/SetupGitHubRelease/task.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
|
||||
"id": "950311ab-f037-4f4f-a875-8a4251e2dbd5",
|
||||
"name": "SetupGitHubRelease",
|
||||
"friendlyName": "Setup GitHub Release",
|
||||
"description": "Downloads and installs a binary from the latest GitHub release and adds it to PATH.",
|
||||
"helpMarkDown": "Matches release assets by platform and architecture, downloads, extracts, locates the binary, caches it, and prepends its directory to PATH.",
|
||||
"category": "Utility",
|
||||
"author": "Slawomir Koszewski",
|
||||
"version": {
|
||||
"Major": 1,
|
||||
"Minor": 0,
|
||||
"Patch": 0
|
||||
},
|
||||
"instanceNameFormat": "Setup GitHub release from $(repository)",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "repository",
|
||||
"type": "string",
|
||||
"label": "Repository",
|
||||
"defaultValue": "",
|
||||
"required": true,
|
||||
"helpMarkDown": "GitHub repository in owner/repo format."
|
||||
},
|
||||
{
|
||||
"name": "fileName",
|
||||
"type": "string",
|
||||
"label": "File Name",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"helpMarkDown": "Asset name or regex prefixed with ~."
|
||||
},
|
||||
{
|
||||
"name": "binaryName",
|
||||
"type": "string",
|
||||
"label": "Binary Name",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"helpMarkDown": "Binary name or regex prefixed with ~. Defaults to repository name."
|
||||
},
|
||||
{
|
||||
"name": "fileType",
|
||||
"type": "string",
|
||||
"label": "File Type",
|
||||
"defaultValue": "archive",
|
||||
"required": false,
|
||||
"helpMarkDown": "archive, package, or custom regex pattern for file extension matching."
|
||||
},
|
||||
{
|
||||
"name": "updateCache",
|
||||
"type": "pickList",
|
||||
"label": "Update Cache",
|
||||
"defaultValue": "false",
|
||||
"required": false,
|
||||
"helpMarkDown": "false: use any cached version. true: use current latest release and cache if needed. always: always download latest and refresh cache.",
|
||||
"options": {
|
||||
"false": "false",
|
||||
"true": "true",
|
||||
"always": "always"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "debug",
|
||||
"type": "boolean",
|
||||
"label": "Debug",
|
||||
"defaultValue": "false",
|
||||
"required": false,
|
||||
"helpMarkDown": "Logs discovered files while searching for the binary."
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"type": "string",
|
||||
"label": "GitHub Token",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"helpMarkDown": "Optional GitHub token for private repos or higher API limits. If empty, uses GITHUB_TOKEN if available."
|
||||
}
|
||||
],
|
||||
"execution": {
|
||||
"Node20_1": {
|
||||
"target": "dist/SetupGitHubRelease/src/index.js"
|
||||
}
|
||||
},
|
||||
"minimumAgentVersion": "3.225.0"
|
||||
}
|
||||
14
task/SetupGitHubRelease/tsconfig.json
Normal file
14
task/SetupGitHubRelease/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": ".."
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user