buddy-bot
Version:
Automated & optimized dependency updates for JavaScript & TypeScript projects. Like Renovate & Dependabot.
40 lines (24 loc) • 9.73 kB
JavaScript
// @bun
import{A as F,B as R}from"./chunk-q3tv2y4q.js";import"./chunk-zmck1ahy.js";import{D,H as B}from"./chunk-jcxe2rnh.js";async function k(H,K){try{let E=K.split("/").pop()||"";if(E==="package.json"){let O=JSON.parse(H),J=[];return G(O.dependencies,"dependencies",K,J),G(O.devDependencies,"devDependencies",K,J),G(O.peerDependencies,"peerDependencies",K,J),G(O.optionalDependencies,"optionalDependencies",K,J),{path:K,type:"package.json",content:H,dependencies:J}}if(F(K))return await R(K,H);if(E==="composer.json"||E==="composer.lock"){let{parseComposerFile:O}=await import("./chunk-a37jncfn.js");return await O(K,H)}return null}catch{return null}}function G(H,K,E,O){if(!H)return;for(let[J,S]of Object.entries(H))O.push({name:J,currentVersion:S,type:K,file:E})}function y(H){return"bun"}function m(H,K){if(K)return K;if(H.length===1){let S=H[0];return`chore(deps): update dependency ${S.name} to ${S.newVersion}`}let E=H.filter((S)=>S.updateType==="major"),O=H.filter((S)=>S.updateType==="minor"),J=H.filter((S)=>S.updateType==="patch");if(E.length>0)return`chore(deps): update ${E.length} major dependencies`;else if(O.length>0)return`chore(deps): update ${O.length} minor dependencies`;else return`chore(deps): update ${J.length} patch dependencies`}function f(H,K){if(K)return K;if(H.length===1){let O=H[0];return`chore(deps): update dependency ${O.name} to v${O.newVersion}`}let E=H.filter((O)=>O.updateType==="major");if(E.length>0)return`chore(deps): update ${E.length} major dependencies`;else return"chore(deps): update all non-major dependencies"}function V(H,K){if(K)return K;let E=`This PR contains the following updates:
`;E+=`| Package | Change | Age | Adoption | Passing | Confidence |
`,E+=`|---|---|---|---|---|---|
`;for(let J of H){let S=`\`${J.currentVersion}\` -> \`${J.newVersion}\``,Q=J.metadata?.homepage?`[${J.name}](${J.metadata.homepage})`:J.name;E+=`| ${Q} | ${S} | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) |
`}E+=`
---
`;let O=H.filter((J)=>J.releaseNotesUrl);if(O.length>0){E+=`### Release Notes
`;for(let J of O)if(J.releaseNotesUrl)E+=`<details>
<summary>${J.name}</summary>
`,E+=`[Release Notes](${J.releaseNotesUrl})
`,E+=`</details>
`}return E+=`### Configuration
`,E+=`\uD83D\uDCC5 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
`,E+=`\uD83D\uDEA6 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
`,E+=`\u267B **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
`,E+=`\uD83D\uDD15 **Ignore**: Close this PR and you won't be reminded about this update again.
`,E+=`---
`,E+=` - [ ] <!-- rebase-check -->If you want to update/retry this PR, check this box
`,E+=`---
`,E+="This PR was generated by [Buddy](https://github.com/stacksjs/buddy-bot).",E}function P(H,K="buddy"){let E=new Date().toISOString().slice(0,10).replace(/-/g,"");if(H.length===1){let J=H[0],S=J.name.replace(/[^a-z0-9-]/gi,"-");return`${K}/update-${S}-to-${J.newVersion}-${E}`}if(H.filter((J)=>J.updateType==="major").length>0)return`${K}/update-major-dependencies-${E}`;else return`${K}/update-dependencies-${E}`}function j(H){let K=new Map;for(let E of H){let O=`${E.name}:${E.currentVersion}:${E.newVersion}`,J=K.get(O);if(!J)K.set(O,E);else{let S=C(E.file),Q=C(J.file);if(S>Q)K.set(O,E)}}return Array.from(K.values())}function C(H){if(H==="package.json")return 3;if(H.endsWith("composer.json"))return 2;if(H.includes(".github/workflows/"))return 1;return 0}function h(H){let K=[],E=j(H),O=E.filter((Q)=>Q.updateType==="major"),J=E.filter((Q)=>Q.updateType==="minor"),S=E.filter((Q)=>Q.updateType==="patch");for(let Q of O)K.push({name:`Major Update - ${Q.name}`,updates:[Q],updateType:"major",title:`chore(deps): update dependency ${Q.name} to ${Q.newVersion}`,body:V([Q])});if(J.length>0||S.length>0){let Q=[...J,...S];K.push({name:"Non-Major Updates",updates:Q,updateType:J.length>0?"minor":"patch",title:"chore(deps): update all non-major dependencies",body:V(Q)})}return K}function u(H){let K={major:3,minor:2,patch:1};return H.sort((E,O)=>{let J=K[E.updateType],S=K[O.updateType];if(J!==S)return S-J;return E.name.localeCompare(O.name)})}function c(H,K){let E=H.replace(/^[v^~>=<@]+/,""),O=K.replace(/^[v^~>=<@]+/,"");try{if(Bun.semver.order(O,E)<=0)return"patch"}catch{return"patch"}try{let J=E.split(".").map(($)=>parseInt($,10)),S=O.split(".").map(($)=>parseInt($,10));while(J.length<3)J.push(0);while(S.length<3)S.push(0);let[Q,X,_]=J,[Z,Y,z]=S;if(Z>Q)return"major";if(Z===Q&&Y>X)return"minor";if(Z===Q&&Y===X&&z>_)return"patch"}catch{try{if(Bun.semver.satisfies(O,`~${E}`))return"patch"}catch{}try{if(Bun.semver.satisfies(O,`^${E}`))return"minor"}catch{}}return"major"}function g(H,K){try{return Bun.semver.satisfies(H,K)}catch{return!1}}async function l(H,K,E){if(!H)throw new Error("GitHub token is required");try{let O=await fetch(`https://api.github.com/repos/${K}/${E}/pulls?state=open`,{headers:{Authorization:`Bearer ${H}`,Accept:"application/vnd.github+json","User-Agent":"buddy-bot"}});if(!O.ok)throw new Error(`GitHub API error: ${O.status} ${O.statusText}`);return(await O.json()).filter((Q)=>{if(!Q.body)return!1;return/- \[x\] <!-- rebase-check -->.*(?:want to (?:rebase|update)\/retry this PR|If you want to (?:rebase|update)\/retry)/i.test(Q.body)}).map((Q)=>({number:Q.number,branchName:Q.head.ref}))}catch(O){throw new Error(`Failed to check for rebase requests: ${O}`)}}function w(H){let K=[],E=H.match(/\|[^|]*\|[^|]*\|[^|]*\|[^|]*\|/g);if(E)for(let O of E){let J=O.match(/\[([^\]]+)\]\([^)]*\)/);if(J)K.push(J[1])}return K}async function s(H,K,E){if(await x(H,K,E))return!0;if(await M(H,K,E))return!0;return!1}async function x(H,K,E){if(!(K.packages?.respectLatest??!0))return E.debug(`\uD83D\uDD0D PR #${H.number}: respectLatest is false, skipping auto-close`),!1;let J=["latest","*","main","master","develop","dev"],S=H.body.toLowerCase();if(!J.some((Y)=>S.includes(Y)))return E.debug(`\uD83D\uDD0D PR #${H.number}: No dynamic versions found in PR body`),!1;E.debug(`\uD83D\uDD0D PR #${H.number}: Found dynamic versions in PR body`);let X=w(H.body);E.debug(`\uD83D\uDD0D PR #${H.number}: Extracted packages: ${X.join(", ")}`);let _=X.filter((Y)=>{let z=new RegExp(`\\|\\s*\\[${Y.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\]\\([^)]+\\)\\s*\\|\\s*([^|]+)\\s*\\|`,"i"),$=H.body.match(z);if(!$){let N=new RegExp(`${Y.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}[^\\w]*[:=]\\s*["']?([^"'
]+)["']?`,"i"),I=H.body.match(N);if(!I)return E.debug(`\uD83D\uDD0D PR #${H.number}: No version pattern found for package ${Y}`),!1;let W=I[1].toLowerCase().trim().replace(/`/g,""),v=J.includes(W);return E.debug(`\uD83D\uDD0D PR #${H.number}: Package ${Y} has version ${W}, isDynamic: ${v}`),v}let A=$[1].trim(),L=A.match(/^([^\u2192]+)\u2192/);if(!L)return E.debug(`\uD83D\uDD0D PR #${H.number}: Could not parse version change for package ${Y}: ${A}`),!1;let T=L[1].trim().toLowerCase().replace(/`/g,""),q=J.includes(T);return E.debug(`\uD83D\uDD0D PR #${H.number}: Package ${Y} has current version ${T}, isDynamic: ${q}`),q}),Z=_.length>0;return E.debug(`\uD83D\uDD0D PR #${H.number}: Packages with dynamic versions: ${_.join(", ")}`),E.debug(`\uD83D\uDD0D PR #${H.number}: Should auto-close: ${Z}`),Z}async function M(H,K,E){let O=K.packages?.ignorePaths;if(!O||O.length===0)return E.debug(`\uD83D\uDD0D PR #${H.number}: No ignorePaths configured, skipping auto-close`),!1;let J=U(H.body);if(J.length===0)return E.debug(`\uD83D\uDD0D PR #${H.number}: No file paths found in PR body`),!1;E.debug(`\uD83D\uDD0D PR #${H.number}: Found file paths: ${J.join(", ")}`);let{Glob:S}=globalThis.Bun,Q=J.filter((X)=>{let _=X.replace(/^\.\//,"");return O.some((Z)=>{try{return new S(Z).match(_)}catch(Y){return E.debug(`Failed to match path ${_} against pattern ${Z}: ${Y}`),!1}})});if(Q.length>0)return E.debug(`\uD83D\uDD0D PR #${H.number}: Contains files now in ignorePaths: ${Q.join(", ")}`),!0;return E.debug(`\uD83D\uDD0D PR #${H.number}: No files match ignorePaths patterns`),!1}function U(H){let K=[],E=/\|\s*\[[^\]]+\]\([^)]*\)\s*\|[^|]*\|\s*\*\*([^*]+)\*\*\s*\|/g,O;while((O=E.exec(H))!==null){let X=O[1].trim();if(X&&!K.includes(X))K.push(X)}let J=/\*\*([^*]+\.(?:json|yaml|yml|lock))\*\*/g;while((O=J.exec(H))!==null){let X=O[1].trim();if(X&&!K.includes(X))K.push(X)}let S=/\|[^|]+\|[^|]+\|([^|]+)\|[^|]*\|/g;while((O=S.exec(H))!==null){let X=O[1].trim();if(X&&(X.includes("/")||/\.(?:json|yaml|yml|lock)$/.test(X))&&!K.includes(X))K.push(X)}let Q=/(?:^|\s)([\w-]+(?:\/[\w.-]+)*\/[\w.-]+\.(?:json|yaml|yml|lock))(?:\s|$)/gm;while((O=Q.exec(H))!==null){let X=O[1].trim();if(X&&!K.includes(X))K.push(X)}return K}export{u as sortUpdatesByPriority,g as satisfiesRange,k as parsePackageFile,h as groupUpdates,c as getUpdateType,P as generateBranchName,f as formatPRTitle,V as formatPRBody,m as formatCommitMessage,w as extractPackageNamesFromPRBody,y as detectPackageManager,l as checkForRebaseRequests,s as checkForAutoClose};
export{k as r,y as s,m as t,f as u,V as v,P as w,h as x,u as y,c as z};
//# debugId=EEF3C081C366AEA964756E2164756E21