From 9b2efb7fd8aa023f45a179b49e32cd6a7c50b55a Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Mon, 26 May 2025 20:20:17 +0200 Subject: [PATCH] Add support for pep440 version specifiers (#150) Fixes: #147 --- .github/workflows/test.yml | 18 ++++++++++++++++++ README.md | 14 +++++++++++--- dist/ruff-action/index.js | Bin 1487917 -> 1507116 bytes package-lock.json | 11 +++++++++++ package.json | 1 + src/download/download-version.ts | 24 ++++++++++++++++++++++-- 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0826dc8..fc7d18c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -203,6 +203,23 @@ jobs: fi env: RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }} + test-pep440-version-specifier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install version 0.11.11 + id: ruff-action + uses: ./ + with: + version: ">=0.11.10,<0.12.0" + src: __tests__/fixtures/python-project + - name: Correct version gets installed + run: | + if [ "$RUFF_VERSION" != "0.11.11" ]; then + exit 1 + fi + env: + RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }} test-checksum: runs-on: ${{ matrix.inputs.os }} strategy: @@ -298,6 +315,7 @@ jobs: - test-default-version-from-pyproject-optional-dependencies - test-default-version-from-requirements - test-semver-range + - test-pep440-version-specifier - test-checksum - test-with-explicit-token - test-args diff --git a/README.md b/README.md index e444b08..bbd0bd2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A GitHub Action to run [ruff](https://github.com/astral-sh/ruff). This action is commonly used as a pass/fail test to ensure your repository stays clean, abiding the [rules](https://docs.astral.sh/ruff/rules/) specified in your -configuration. Though it runs `ruff check` by default, the action can do +configuration. Though it runs `ruff check` by default, the action can do anything `ruff` can (ex, fix). ## Contents @@ -18,7 +18,7 @@ anything `ruff` can (ex, fix). - [Install specific versions](#install-specific-versions) - [Install the latest version](#install-the-latest-version) - [Install a specific version](#install-a-specific-version) - - [Install a version by supplying a semver range](#install-a-version-by-supplying-a-semver-range) + - [Install a version by supplying a semver range or pep440 specifier](#install-a-version-by-supplying-a-semver-range-or-pep440-specifier) - [Install a version from a specified version file](#install-a-version-from-a-specified-version-file) - [Validate checksum](#validate-checksum) - [GitHub authentication token](#github-authentication-token) @@ -116,9 +116,10 @@ the latest version is installed. version: "0.4.4" ``` -#### Install a version by supplying a semver range +#### Install a version by supplying a semver range or pep440 specifier You can specify a [semver range](https://github.com/npm/node-semver?tab=readme-ov-file#ranges) +or [pep440 specifier](https://peps.python.org/pep-0440/#version-specifiers) to install the latest version that satisfies the range. ```yaml @@ -135,6 +136,13 @@ to install the latest version that satisfies the range. version: "0.4.x" ``` +```yaml +- name: Install a pep440-specifier-satisfying version of ruff + uses: astral-sh/ruff-action@v3 + with: + version: ">=0.11.10,<0.12.0" +``` + #### Install a version from a specified version file You can specify a file to read the version from. diff --git a/dist/ruff-action/index.js b/dist/ruff-action/index.js index a07726453ec2611f9072b92880707301138869fd..f3bd5c580d49ecb9bbf49029b2b0189ef43a614d 100644 GIT binary patch delta 17243 zcmc&+U2Gdyc7`Qcwi)>^ROC&ZWUm|}ByEcNv9lY?rew$QCT_BhW2XtQvSN?Oku>p$ z!_1JD6iJ>ID6nsfra>|2Lx1wnZHuPcWU)oiVq4T`k(ags_Njl{hrF}}iURG+0!7=P z-#O>r`5`GMaU9eLso~7I=bU@)`Mc+y$shddci#JS?iYS($B+8X-X1tHb?TeZ%faAt z(M$i_Kls>&x@Eaey{u}kZ8gfuUTeCRgNvr+2hqE~*Z;`Vr%ruivUEC^t9gx}r8bn? zDl69p=$mELz~3eM;9kvJ!65wb<%&lyojUoAQ>oE8r4}8xW&34ZtypVUt(Frkt~-q- zzTq^oH?Ew!^xTE(m(RWO%7rVJ2qIv3#}4QRvwp>DfP?7HzxO{}JTdw7Qz>E~@P_A? z)r!-gKTWGuTP`c7QHv&jb?+lPpPm9|k@dT|L*e+ix@G%;<24Lg!Y?wxg^>y_NiKFd zhbxTnnznDXJRiRx75c^_y0)kFC4__<5EFmDIjt|jF>Wjo99@QVO?Qk8ajB(8#BziL_dL#1f zIj^kH(vmXbA(0f$6d+8NPT@?Iu32`4DqYK2yK@JE4+m8P1?cvA5r>0I#oj5TyK6&!Q(@#xJCH9m|%69FQi@?b% zd$A#mx^_#^0|;K8)3VS_hQeJ9O}CvzRTNlgG~X8-P@uh{L9j`swsO(i?+p)!1X@z0 z{pWn&TCX?(|1HW$GgK4Lg2>QW;cQyX(eHV}tzy2i12i|Y`Z0!h50F0bAkENe#%kz_ z>bZ6UbNsf|TCTvm^6Vi79*ypNv~%QFo*w8sor?}G^*zi|(?r!+h6j;t$1;pvY%Dqr zr?sv&H;rr{adX#js5N|SvL_M)4IE(#NsPM#ON>NgrD?(;v%J)-8kW4C1wA ztSBr-8=kTZ0^{Av^mG-mm5j(h!K7B5*0QqP&{f_d?2-aJ8K`eLE^;FEmhF21aIJW^ z?0Q9A^?;_}x~d)6OoKeIP2-g75Q}x+YXY6iw;JB6pu<$^3AQ!@ysMeTSWgAsN@&9; zfL;TkkZ6_(K|{5yn}Qum(-K_1J?7g&7VIxrwVMzGkPr_w&-d*bjM%Tkr&^6Vk_aFG zoTXarrVE~N54`JHE?X_N==sWPhd#LQ;f9vT?^Wxc#-7-NfAhEVU4etOeLXNd&&0B7O|NytkYcBqA)uW zv+d%B;mUAf+ztnM%|(bDkfs=OkrG>moL)!~Tbh(m!7z}a!I{~1PB*3l;n=R%g#E!Y z==ILfLSOY#TSTWCdIt4w=$ZZ5q38HfH?L6Ti$qi=a7rptt!F-sk zCJ1096YPXsatX3{Gfl~#$W)va_y$sS$VvPkl+YNJXdkkZ%NH)6JjvF>Fk|YR+g!F( zqrGCo6jiA42BH^w0_LfCXee}!HqT|SYp*#qZ^^fs%MK>%t|!ATX>!>CAQKW7S=g(~ z@M-XbAnoD=SvBSlsE9 zRCOkLcQQBZg2@HjFFK_X0^?k4cG&yQBS_B0kISl1n5RvaQtVa{JL9x`j)Nn1^F1OV zbWVrE`P0#4xbILu_R`5V@bE^wW0owttOB^p#*(wR9-aGP?vY7dQh-{DCBeM0u}APh z0YNPwj3E85t3}^ifx4_fe$l(_{t@>x_oV499RnA;qP|`XD6rnuYY_5DY&aSqI$O*= z9{u`zeZ!&PAOMLD>1_)_5IZXbmu&9A+va;GZ!EX9>_;yYbNODJ5WAXN!-k1^XVjFz zpwlItB**L9F>r3OgMZ%bckq84j_pg!@2*^*_<~$db#RT+gz%hF++~EME3!%#>+mwp zqGS6)hmt)fz6YJ?1xh*Y4eJK2za)-{2-t_k3KR_u^*jE&dDQ^b>z>IreH{zJl4f?YbQl84vU`W>t(fI{3pqc_tXW_Q!pb z;f97YjLxwQyejSo$&Xn)qb)Qg`PZQh6;zqr;zYc0K&?%Xn30@INsUOOSI1SzDLNq} zJE4DO6s82~b1D86*^2bDZ`wBBOg2=nGz>LJ5gM)FJH8kf<4@1^R3E zAW&U*HFFXX$9mT#21Bvyfl zbaZEWU^tq1e&^uS9NZk8d{D}Y^sEyywh7`!K%SuCWBNWy-yH2CPF z9e^2c8~yV0{SQTt|LN{suXVV9`{o@!{&C;K3&eap6T^^pah1SzYIbq5R6)tXE*5cq z)5dnLIzuNpZJUdB6D5S(E(9DuP+)4bT{rskpY0h5J2g8kO-*iF^)jwxTYzp)(rNNI zu~FFCW&;lXFo?c?OdlXwt}Jfw=Wb!lO-&0O!*=!c%owk$M1{fbT8Uh7!zzi{C|xJ zN`-N9`sEh?Ue`YQ{$KX(k3KrEZ+{<72o8qB`JCCr(P{MY{*ithV@GelpL?E;rC*`5 z8f4>K*{iovc_AO#2oR1aF!|U(qaJ7bD}k;ct8-1OhI=mxSlLwB=-g(iGEwFlEDd_* z>azw2m1SEBy)Rxof8o;A3z{OTE(Ga&9*VkDECeq;>H>j-L+^FMNab59XR{-$V;|$V zK_%%Gc=f`Ss~2Co6rbRmJvUBnrP1J33H)3Ycrepw@DiP^M`w@iI~-*dqnurz;Mvx`4Nx%tW)9?pph1=FvP5duw%H==ZrX^=>I1yZdN z0Q#)Pi!IbqWUK207v6-@;iQMx1IrGP7elYfVSA2F;UNQ@zvG)u*i(B}z{F^{dEtt^ zWUpa(!(LUmzOdFT7G5VoXJ$jPJWA*s%rE?aFz6oe9mDCmvKoeJtpD@D}1HZZ-o z#xcixOs;Clbb_W`*De{e&C<+7{ zTj`M-YRUK7%|LDOaA8W6kn>>3{~36P0y!u&?uZ&EgSC_FVQ z8Fl24{$$1id30yJ@33I4;#5mhDAPsO0Am-VwxS<=Fg!BFsc+$S70PY6C&7})iAj^x zr|M17+t2Md6#dPCeYxmwe|zLW^jjb9$VKn}(T;)KXskuixgQMY_faCvNO&s~{bz3A zAsP44^uYcck&szMzxbnkeouDrBUFvy!3ewYwIJ$dV0U!j`y;!VYb_vP1ago zjOfX7ZeR52`F!s57HM8GSpy2Sa4aJ$0S*kQR&U%|vKMlBILlQKD43~WHMS|CW z6^K~p$w6eT4UR-#zumv-djU!4V>?Eg5QPfbSX-2aT_8*F>!~I_$*7NWX zu`me%q9>1p*a`TpqVX*_{N>_<@)p;qh&^q zjVMwcO4dnx1}Iz@7s+*;j>j-{?a+k2ULwOrtosQzDBmcK^tizgr`b+$J<%vWGVD^# z0UHV(o%{R#{J19K+x0dgFq&@yt^XBPeEl zpeCrc%5aWaK5-8u<}dmU4aa#n^j)+a-{~HMIN%!Dq^#JOWmKx{8X_jJYc(cfta(n; zMZZRD{bn4QbK*tJ$h0wZG(1?;@^ZCh`K{nJoWd3Pw+<3&P1YvyuLjW!j$JTLyRL)% zJ9nIpKK<|9qu&%atid|lPZB(6F=1cISnwmd{!e>H-q~LmjNTvJF%bRSvzR=|FDtls zO;XeDI<1LMl4vy`vW_+lExYU^k#oG#{P0LjB(@v6)8z$kcHRX|zLn8d@p?K!#2QUH z9RKK{-kqqUPY(7Eb2*bU6p|-{#PNxIb~*$j$>wAmM`a7HeVHS_;V)ZaL7G2?G7BU@ zEfa-fg_6!7E0k2F1NpZqe9o7cExX_z1f*96$=N8SY@JZ=eDE9j=sQ2{%Z0HS-I%E! z-QWr7Td<-kZgmdbx*>Lzj<~cg$ej&WvZ79aj;Y!*wMbNX4sl~Hyos<^t-@t7P5J%g zlNzwoFp_oBf)ndAX^j?=p=)wrBkXvEDE3qKD>5ZVyNr&;IAdAI@oS3fX@yM4%%Qgq zNfJq_kZ{P!O`J1nVU{9ms6QVjP|fxNc80#;0ylFQB`Wlx`2y@FG<31w0uG<-%fV;EB$-g9>*H8NuG}7{Pi~-0_33{G#+fS>oAgxjO(+sFp&f_&hbL39n*+Q? zq|-@hCr!cVV!!~kQAaPozVmB3ewbaU-jssbIp}!dmh3OF6P`9(OWD;FDMHN(!5Jgipw)qN#26=fT)8vyLee7s+N^ zPn>GthI3q+riTpcA>=UzVG`{1#-u?k`*hm&3qQ%u-b^iC5CXx!ZRB7c84~UcQQE{| z@TN~hP;wS32C#=L%_D=OF=g0{=dT%v+3qP1n57m6?XqOaLvGuP=h=h07AA&ZCGj28 z&@}Hp37e@(nBHam?^i_7l+8=h8Q#x#l2ywxL zF7EOY2;8h`YmwIpBwk3ZWxHZW2Q4ahguUt=jK%mE34|t*M?I!4#fTRAG835D*x}-B z2%MB~z9l^IEP57TP;Ht$mM(W0#{$NvR+jJb$AAz$2muluAu- z#mQQfxN?(l%{3bemlSMAby4OMXZYa|_rS+h)VhQT*?OQ$6}vH}YAUTppG>=j21KO= zD3F{`ck#5+-Bve{7RETTb?j=a|Aoxct zI5%xNZ^4W5G2?a3T~Q-q|B5%Y1TFn)nBj0UsqtYa0%ip{#@ZUd$Tb~5>JCQ zrUXtCf=fuz=_I2E*5T)Y-{2uAADYCr+!moec~U}p@t)dNMLLQaJQq%ma?J*zuksW(*fs|7-VLt7B$ z6dFkgK0NG+?nQ1&HSR(;XKI9^6bVX$@y79^8~iNZfut1%P?SoBTy@Xv__wt*F+6(N zMNatBZ@b7dXn_GDq2gMD;(-}se3Ag_Qa1}9?dRm}aIVkCKIEP}w3FgQhg)c!8l2+< z++#-@H5Lh{IDmHIo>KH%0tggw#^R#CI`C=^d~RL3r=3;>%!zu2qr#V261>dF-3wrt zI|@y&7j%QVI5H$$-5x}h!A2>@v#>5iW4Vj`%d1>Ncg97FTxcHGEBj1`&@0e z@sdM~%8*M0X68ftBI)o;L}#AiiQY19B|YlqAq}LoSN2rgXrLttnWKr2^aD~)2F^)S zA#9e8P4K6)dr&aPha;?akQbptCt?qLKtZT{9Osnc9>lv~AuBIX2_THSQ!YshvQ{46 zIgtw?hcT*WigHO-w?v1ajnGSi#KKTN@Dlcdq|*W%zYalzrLOJgn6DwCDgs_o((4$6wC7a3EOtf&|s z0l<;6nk=g$0(7J#s(EZ&OFu;?o(bP$no8-Tu<^Od^|ASJ5d-e>ff&UYs<&!TrE?q9 zx-MClidb@*KgH7)cb?Nl)}B$b2UHAXvWPgsY%4Kc=Sb4G4e%hT9}ANYM-VMgBG*BH zak9DzfU!bNLT-}olUkZ2@{0#~42F{6MX10=G9n!zWLRugM4nNa)+XXw8DQ=ppf~yi zgiC9NA&oBv=?dwrio$lPG>Q3xxG5jJ5+TO7n%@3c zWOQ>&`Z>OP_I4jW{rC*vvlE{|e0Jfp8=pP+SOQxis%1=j&YlHddA7}UHKm6;V{Lk--&OX>b zQZi#r#nIQ1o}JeFvlO4dox$lRTKLqTlhS>wQCKzQrebmcax! zOYilV|1|>zd;QvmoUu=_w76TIT#a^Tp;CxG|ikwMa(6bxvKqdv-!PI{dj-=yC;X~GmOteAD$c@ I`LEynKivH>F#rGn delta 147 zcmZ4UFM92ZsD>8CEldt|?Xt(2fS4JGS%8=oh}nRc9f&!Am=lP(fS4PId4QM~i1~n+ zABY8jSa7@SaiNX%+u7WO^ZBMP@e~%}Oe{;x%t=hjNu9pWQ`m0$+K0?slP4&$Z+{dj a9LhfZNDh~9yKy`SivY3ccH?-lpYs8R!Z)V? diff --git a/package-lock.json b/package-lock.json index f3c6936..044d204 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@octokit/core": "^6.1.4", "@octokit/plugin-paginate-rest": "^11.4.3", "@octokit/plugin-rest-endpoint-methods": "^13.3.1", + "@renovatebot/pep440": "^4.1.0", "smol-toml": "^1.3.1" }, "devDependencies": { @@ -350,6 +351,16 @@ "@octokit/openapi-types": "^23.0.1" } }, + "node_modules/@renovatebot/pep440": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@renovatebot/pep440/-/pep440-4.1.0.tgz", + "integrity": "sha512-mo2RxnOSp78Njt1HmgMwjl6FapP4OyIS8HypJlymCvN7AIV2Xf5PmZfl/E3O1WWZ6IjKrfsEAaPWFMi8tnkq3g==", + "license": "Apache-2.0", + "engines": { + "node": "^20.9.0 || ^22.11.0", + "pnpm": "^9.0.0" + } + }, "node_modules/@types/node": { "version": "22.13.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", diff --git a/package.json b/package.json index 6d6eb76..809a2c7 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@octokit/core": "^6.1.4", "@octokit/plugin-paginate-rest": "^11.4.3", "@octokit/plugin-rest-endpoint-methods": "^13.3.1", + "@renovatebot/pep440": "^4.1.0", "smol-toml": "^1.3.1" }, "devDependencies": { diff --git a/src/download/download-version.ts b/src/download/download-version.ts index 0158f1e..a2440f0 100644 --- a/src/download/download-version.ts +++ b/src/download/download-version.ts @@ -3,6 +3,7 @@ import * as tc from "@actions/tool-cache"; import * as path from "node:path"; import { promises as fs } from "node:fs"; import * as semver from "semver"; +import * as pep440 from "@renovatebot/pep440"; import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants"; import type { Architecture, Platform } from "../utils/platforms"; import { validateChecksum } from "./checksum/checksum"; @@ -124,8 +125,8 @@ export async function resolveVersion( return version; } const availableVersions = await getAvailableVersions(githubToken); - const resolvedVersion = tc.evaluateVersions(availableVersions, version); - if (resolvedVersion === "") { + const resolvedVersion = maxSatisfying(availableVersions, version); + if (resolvedVersion === undefined) { throw new Error(`No version found for ${version}`); } core.debug(`Resolved version: ${resolvedVersion}`); @@ -195,3 +196,22 @@ async function getLatestRelease( }); return latestRelease; } + +function maxSatisfying( + versions: string[], + version: string, +): string | undefined { + const maxSemver = tc.evaluateVersions(versions, version); + if (maxSemver !== "") { + core.debug(`Found a version that satisfies the semver range: ${maxSemver}`); + return maxSemver; + } + const maxPep440 = pep440.maxSatisfying(versions, version); + if (maxPep440 !== null) { + core.debug( + `Found a version that satisfies the pep440 specifier: ${maxPep440}`, + ); + return maxPep440; + } + return undefined; +}