[{"data":1,"prerenderedAt":650},["ShallowReactive",2],{"navigation_docs":3,"-contributing-guidelines":195,"-contributing-guidelines-surround":645},[4,23,65,87,133,155,173],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":22},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,14,18],{"title":11,"path":12,"stem":13},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction",{"title":15,"path":16,"stem":17},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":19,"path":20,"stem":21},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start",false,{"title":24,"icon":25,"path":26,"stem":27,"children":28,"page":22},"Guides","i-lucide-compass","\u002Fguides","2.guides",[29,33,37,41,45,49,53,57,61],{"title":30,"path":31,"stem":32},"Authenticate","\u002Fguides\u002Fauthentication","2.guides\u002F1.authentication",{"title":34,"path":35,"stem":36},"Work with several forges","\u002Fguides\u002Fmultiple-forges","2.guides\u002F2.multiple-forges",{"title":38,"path":39,"stem":40},"Configure from the environment","\u002Fguides\u002Fenvironment","2.guides\u002F3.environment",{"title":42,"path":43,"stem":44},"Receive webhooks","\u002Fguides\u002Fwebhooks","2.guides\u002F4.webhooks",{"title":46,"path":47,"stem":48},"Check what a forge supports","\u002Fguides\u002Fcapabilities","2.guides\u002F5.capabilities",{"title":50,"path":51,"stem":52},"Handle errors and rate limits","\u002Fguides\u002Ferrors","2.guides\u002F6.errors",{"title":54,"path":55,"stem":56},"Page through results","\u002Fguides\u002Fpagination","2.guides\u002F7.pagination",{"title":58,"path":59,"stem":60},"Browser bundles","\u002Fguides\u002Fbundling","2.guides\u002F8.bundling",{"title":62,"path":63,"stem":64},"Test your code","\u002Fguides\u002Ftesting","2.guides\u002F9.testing",{"title":66,"icon":67,"path":68,"stem":69,"children":70,"page":22},"Concepts","i-lucide-lightbulb","\u002Fconcepts","3.concepts",[71,75,79,83],{"title":72,"path":73,"stem":74},"Data model","\u002Fconcepts\u002Fdata-model","3.concepts\u002F1.data-model",{"title":76,"path":77,"stem":78},"Capabilities","\u002Fconcepts\u002Fcapabilities","3.concepts\u002F2.capabilities",{"title":80,"path":81,"stem":82},"Providers and factories","\u002Fconcepts\u002Fproviders","3.concepts\u002F3.providers",{"title":84,"path":85,"stem":86},"Events","\u002Fconcepts\u002Fevents","3.concepts\u002F4.events",{"title":88,"icon":89,"path":90,"stem":91,"children":92,"page":22},"Providers","i-lucide-server","\u002Fproviders","4.providers",[93,97,101,105,109,113,117,121,125,129],{"title":94,"path":95,"stem":96},"Azure DevOps","\u002Fproviders\u002Fazure-devops","4.providers\u002Fazure-devops",{"title":98,"path":99,"stem":100},"Bitbucket Cloud","\u002Fproviders\u002Fbitbucket","4.providers\u002Fbitbucket",{"title":102,"path":103,"stem":104},"Cursor Origin","\u002Fproviders\u002Fcursor-origin","4.providers\u002Fcursor-origin",{"title":106,"path":107,"stem":108},"Forgejo and Codeberg","\u002Fproviders\u002Fforgejo","4.providers\u002Fforgejo",{"title":110,"path":111,"stem":112},"Gitea","\u002Fproviders\u002Fgitea","4.providers\u002Fgitea",{"title":114,"path":115,"stem":116},"Gitee","\u002Fproviders\u002Fgitee","4.providers\u002Fgitee",{"title":118,"path":119,"stem":120},"GitHub","\u002Fproviders\u002Fgithub","4.providers\u002Fgithub",{"title":122,"path":123,"stem":124},"GitLab","\u002Fproviders\u002Fgitlab","4.providers\u002Fgitlab",{"title":126,"path":127,"stem":128},"pushin.eu","\u002Fproviders\u002Fpushin","4.providers\u002Fpushin",{"title":130,"path":131,"stem":132},"Tangled","\u002Fproviders\u002Ftangled","4.providers\u002Ftangled",{"title":134,"icon":135,"path":136,"stem":137,"children":138,"page":22},"Reference","i-lucide-book-marked","\u002Freference","5.reference",[139,143,147,151],{"title":140,"path":141,"stem":142},"Provider API","\u002Freference\u002Fprovider-api","5.reference\u002F1.provider-api",{"title":144,"path":145,"stem":146},"Capability matrix","\u002Freference\u002Fcapability-matrix","5.reference\u002F2.capability-matrix",{"title":148,"path":149,"stem":150},"Errors","\u002Freference\u002Ferrors","5.reference\u002F3.errors",{"title":152,"path":153,"stem":154},"JSON Schemas","\u002Freference\u002Fjson-schemas","5.reference\u002F5.json-schemas",{"title":156,"icon":157,"path":158,"stem":159,"children":160,"page":22},"Examples","i-lucide-boxes","\u002Fexamples","6.examples",[161,165,169],{"title":162,"path":163,"stem":164},"Inbox CLI","\u002Fexamples\u002Finbox-cli","6.examples\u002F1.inbox-cli",{"title":166,"path":167,"stem":168},"Label bot","\u002Fexamples\u002Flabel-bot","6.examples\u002F2.label-bot",{"title":170,"path":171,"stem":172},"Release digest","\u002Fexamples\u002Frelease-digest","6.examples\u002F3.release-digest",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":22},"Contributing","i-lucide-git-pull-request","\u002Fcontributing","7.contributing",[179,183,187,191],{"title":180,"path":181,"stem":182},"Contribution guide","\u002Fcontributing\u002Fguidelines","7.contributing\u002F1.guidelines",{"title":184,"path":185,"stem":186},"Write a provider","\u002Fcontributing\u002Fwrite-a-provider","7.contributing\u002F2.write-a-provider",{"title":188,"path":189,"stem":190},"Record fixtures","\u002Fcontributing\u002Frecord-fixtures","7.contributing\u002F3.record-fixtures",{"title":192,"path":193,"stem":194},"Contributors","\u002Fcontributing\u002Fcontributors","7.contributing\u002F4.contributors",{"id":196,"title":180,"body":197,"description":637,"extension":638,"links":639,"meta":640,"navigation":642,"path":181,"seo":643,"stem":182,"__hash__":644},"docs\u002F7.contributing\u002F1.guidelines.md",{"type":198,"value":199,"toc":627},"minimark",[200,217,222,234,257,261,403,407,493,497,541,548,552,561,569,572,576,590,594,601,610,614,623],[201,202,203,204,208,209,216],"p",{},"Thanks for helping with ",[205,206,207],"code",{},"forges",". This page covers how to set up the repository, the checks a change has to pass and the rules that keep the providers consistent. By taking part, you agree to the ",[210,211,215],"a",{"href":212,"rel":213},"https:\u002F\u002Fgithub.com\u002Fdanielroe\u002Fforges\u002Fblob\u002Fmain\u002FCODE_OF_CONDUCT.md",[214],"nofollow","Code of Conduct",".",[218,219,221],"h2",{"id":220},"set-up","Set up",[201,223,224,225,230,231,216],{},"You need Node.js 22.18 or later and ",[210,226,229],{"href":227,"rel":228},"https:\u002F\u002Fpnpm.io",[214],"pnpm",". The repository pins the versions it develops with in ",[205,232,233],{},"devEngines",[235,236,241],"pre",{"className":237,"code":238,"language":239,"meta":240,"style":240},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm install\npnpm test:unit\n","sh","",[205,242,243,251],{"__ignoreMap":240},[244,245,248],"span",{"class":246,"line":247},"line",1,[244,249,250],{},"pnpm install\n",[244,252,254],{"class":246,"line":253},2,[244,255,256],{},"pnpm test:unit\n",[218,258,260],{"id":259},"commands","Commands",[262,263,264,277],"table",{},[265,266,267],"thead",{},[268,269,270,274],"tr",{},[271,272,273],"th",{},"Command",[271,275,276],{},"What it does",[278,279,280,291,301,322,336,346,360,373,383,393],"tbody",{},[268,281,282,288],{},[283,284,285],"td",{},[205,286,287],{},"pnpm dev",[283,289,290],{},"Runs the unit tests in watch mode",[268,292,293,298],{},[283,294,295],{},[205,296,297],{},"pnpm test:unit",[283,299,300],{},"Runs the unit tests once",[268,302,303,308],{},[283,304,305],{},[205,306,307],{},"pnpm test:types",[283,309,310,311,314,315,318,319],{},"Type-checks ",[205,312,313],{},"src",", ",[205,316,317],{},"test"," and ",[205,320,321],{},"scripts",[268,323,324,329],{},[283,325,326],{},[205,327,328],{},"pnpm test:capabilities",[283,330,331,332,335],{},"Fails for a capability that a provider declares ",[205,333,334],{},"true"," and no test called",[268,337,338,343],{},[283,339,340],{},[205,341,342],{},"pnpm test:knip",[283,344,345],{},"Finds unused files, exports and dependencies",[268,347,348,353],{},[283,349,350],{},[205,351,352],{},"pnpm test:size",[283,354,355,356,359],{},"Checks the browser bundle budgets. Run ",[205,357,358],{},"pnpm build"," first",[268,361,362,370],{},[283,363,364,314,367],{},[205,365,366],{},"pnpm lint",[205,368,369],{},"pnpm lint:fix",[283,371,372],{},"Lints, and fixes what it can",[268,374,375,380],{},[283,376,377],{},[205,378,379],{},"pnpm capability-matrix",[283,381,382],{},"Regenerates the capability tables in the docs",[268,384,385,390],{},[283,386,387],{},[205,388,389],{},"pnpm record-fixtures \u003Cforge>",[283,391,392],{},"Records responses from a live forge",[268,394,395,400],{},[283,396,397],{},[205,398,399],{},"pnpm check:all",[283,401,402],{},"Runs lint, tests, the engines check, a build and the size check",[218,404,406],{"id":405},"project-layout","Project layout",[262,408,409,419],{},[265,410,411],{},[268,412,413,416],{},[271,414,415],{},"Path",[271,417,418],{},"Content",[278,420,421,431,450,463,473,483],{},[268,422,423,428],{},[283,424,425],{},[205,426,427],{},"src\u002F\u003Cforge>\u002F",[283,429,430],{},"One provider each: its factory, normalisation and webhook handling",[268,432,433,444],{},[283,434,435,314,438,314,441],{},[205,436,437],{},"src\u002Fmodel.ts",[205,439,440],{},"src\u002Fprovider.ts",[205,442,443],{},"src\u002Fdefine.ts",[283,445,446,447],{},"The shared model, the provider interface and ",[205,448,449],{},"defineForgeProvider()",[268,451,452,460],{},[283,453,454,314,457],{},[205,455,456],{},"src\u002Ffake\u002F",[205,458,459],{},"src\u002Ftesting\u002F",[283,461,462],{},"The in-memory forge and the test helpers",[268,464,465,470],{},[283,466,467],{},[205,468,469],{},"test\u002F",[283,471,472],{},"Unit tests, recorded fixtures and the shared recording steps",[268,474,475,480],{},[283,476,477],{},[205,478,479],{},"examples\u002F",[283,481,482],{},"Small, tested projects that use the library",[268,484,485,490],{},[283,486,487],{},[205,488,489],{},"docs\u002F",[283,491,492],{},"The documentation site",[218,494,496],{"id":495},"rules","Rules",[498,499,500,511,517,528,531,538],"ul",{},[501,502,503,504,506,507,510],"li",{},"Declare a capability ",[205,505,334],{}," only when a test calls it. Use ",[205,508,509],{},"'experimental'"," for anything that isn't verified against a recording of the live forge.",[501,512,513,514,516],{},"After you change a provider's capabilities, run ",[205,515,379],{},". A test fails if the docs are out of date.",[501,518,519,520,523,524,527],{},"Import source files with the ",[205,521,522],{},".ts"," extension, so that ",[205,525,526],{},"node scripts\u002F\u003Cname>.ts"," runs without a build.",[501,529,530],{},"Don't add runtime dependencies. Don't import Node.js built-in modules from a provider.",[501,532,533,534,537],{},"Keep errors, warnings and ",[205,535,536],{},"skipped"," reasons free of credentials.",[501,539,540],{},"Add a test for each change. For a new read, record a fixture instead of writing one by hand.",[201,542,543,544,318,546,216],{},"To add a forge or an operation, read ",[210,545,184],{"href":185},[210,547,188],{"href":189},[218,549,551],{"id":550},"commit-messages","Commit messages",[201,553,554,555,560],{},"Commits follow ",[210,556,559],{"href":557,"rel":558},"https:\u002F\u002Fwww.conventionalcommits.org",[214],"Conventional Commits",". Releases are cut from the commit messages, so the type decides the version bump. Use the provider as the scope when a change concerns one forge:",[235,562,567],{"className":563,"code":565,"language":566,"meta":240},[564],"language-text","feat(github): adopt asynchronous direct merges\nfix(gitlab): read nested group paths\ndocs: explain webhook verification\n","text",[205,568,565],{"__ignoreMap":240},[201,570,571],{},"Use the same format for the title of a pull request.",[218,573,575],{"id":574},"pull-requests","Pull requests",[498,577,578,581,587],{},[501,579,580],{},"Keep a pull request to one change.",[501,582,583,584,586],{},"Run ",[205,585,399],{}," before you push. CI runs the same checks.",[501,588,589],{},"Describe what changed and why. Link the issue it closes.",[218,591,593],{"id":592},"writing-documentation","Writing documentation",[201,595,596,597,600],{},"The documentation lives in ",[205,598,599],{},"docs\u002Fcontent",". Write short sentences in the second person, and prefer a code example to a long explanation. Avoid em-dashes and filler words. Run the site locally with:",[235,602,604],{"className":237,"code":603,"language":239,"meta":240,"style":240},"pnpm --filter forges-docs dev\n",[205,605,606],{"__ignoreMap":240},[244,607,608],{"class":246,"line":247},[244,609,603],{},[218,611,613],{"id":612},"reporting-a-problem","Reporting a problem",[201,615,616,617,622],{},"Open an ",[210,618,621],{"href":619,"rel":620},"https:\u002F\u002Fgithub.com\u002Fdanielroe\u002Fforges\u002Fissues",[214],"issue"," with steps to reproduce. For a forge-specific bug, name the forge and, for a self-hosted forge, its version.",[624,625,626],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":240,"searchDepth":253,"depth":253,"links":628},[629,630,631,632,633,634,635,636],{"id":220,"depth":253,"text":221},{"id":259,"depth":253,"text":260},{"id":405,"depth":253,"text":406},{"id":495,"depth":253,"text":496},{"id":550,"depth":253,"text":551},{"id":574,"depth":253,"text":575},{"id":592,"depth":253,"text":593},{"id":612,"depth":253,"text":613},"Set up the repository, run the checks and follow the rules that keep providers consistent.","md",null,{"icon":641},"i-lucide-book-heart",true,{"title":180,"description":637},"jqyOiJQYsh1LuUjFtWZZHXMlj0qH78nHG4CBP8_pa_U",[646,648],{"title":170,"path":171,"stem":172,"description":647,"children":-1},"Print the latest release and the failing pull requests of repositories on any forge.",{"title":184,"path":185,"stem":186,"description":649,"children":-1},"Add a forge by declaring each operation once.",1791294008824]