Skip to content

chore: upgrade octokit to v5 and probot to v14#484

Open
Miablo wants to merge 5 commits into
github-community-projects:mainfrom
capitalone-contributions:another-miablo-octokit
Open

chore: upgrade octokit to v5 and probot to v14#484
Miablo wants to merge 5 commits into
github-community-projects:mainfrom
capitalone-contributions:another-miablo-octokit

Conversation

@Miablo

@Miablo Miablo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Pull Request

This PR will update Octokit and Probot along with updating any files based on the various majors we are updating to.

Closes #329

fixed merge conflicts from #477

Proposed Changes

Upgrades Probot 13 → 14.3.2 and Octokit 3 → 5, aligning the entire @octokit/core dependency tree to a single deduped v7.0.6.

Key changes:

  • probot 13.4.7 → 14.3.2
  • octokit 3.2.2 → ^5.0.5
  • @octokit/auth-app 6.1.1 → ^7.1.5
  • next-auth 4.24.12 → 4.24.14 (fixes nodemailer peer dependency conflict)
  • @probot/octokit-plugin-config added at ^4.0.0
  • @octokit/openapi-webhooks-types-transition replaces @octokit/webhooks-types for test types
  • createNodeMiddleware() now awaited (async in Probot 14)
  • Legacy REST shortcuts replaced with context.octokit.rest.*
  • z.instanceof(Octokit) → z.custom() (Octokit v5 class structure no longer supports instanceof)
  • Non-null assertions added for repository.owner (nullable in Octokit v5 webhook types)

Type workarounds

  1. as any on DataTable columns (3 page files)

Why: @primer/react's DataTable component uses ObjectPaths<Data> for the field prop type. Under moduleResolution: "bundler" (from @tsconfig/next), the generic Data parameter isn't inferred from the data prop and falls back to UniqueRow, which only exposes "id" as a valid field. This is a known issue with @primer/react's draft DataTable generics.

When to remove: When @primer/react updates DataTable to support moduleResolution: "bundler", or when DataTable moves out of drafts with fixed generic inference.

  1. @ts-expect-error on custom properties API (repos/controller.ts)

Why: rest.orgs.getAllCustomProperties() and rest.orgs.createOrUpdateCustomProperty() exist in the GitHub API and work at runtime, but octokit 5's bundled REST types (@octokit/plugin-rest-endpoint-methods) have not yet added these endpoints to their type definitions.

When to remove: When @octokit/plugin-rest-endpoint-methods adds the custom properties endpoints tracked upstream | tracked locally in #485

  1. @ts-expect-error on 'internal' visibility (repos/controller.ts)

Why: The visibility parameter for repos.createInOrg only types "private" | "public" in octokit 5, but "internal" is a valid value for GitHub Enterprise/GHEC orgs.

When to remove: When octokit's REST types add "internal" to the visibility union.

PR #477 Follow-ups

useForks.tsx:19satisfies over as

`satisfies` doesn't apply here — the cast is needed because `.catch(() => error.data)` widens
the return type to `ForksObject | undefined`, breaking inference on `res`. `satisfies` checks
that a value conforms to a type but doesn't narrow it, so `res.organization` would still error.
The `as ForksObject` is safe because the paginate generic is already `<ForksObject>` and `.catch`
returns the same shape via `error.data`.

forks/[forkId]/page.tsx:570satisfies over as

`satisfies` won't resolve this one. The root issue is that under `moduleResolution: "bundler"`
(from `@tsconfig/next`), DataTable's `Data` generic isn't inferred from the `data` prop and falls
back to `UniqueRow`, which only exposes `"id"` as a valid `field` value. `satisfies` checks shape
conformance but doesn't change how the generic is inferred — entries like `field: 'name'` would
still error. Updated the comment in the code to explain this. The workaround stays until
`@primer/react` fixes generic inference for DataTable (currently a draft component).

controller.ts:37 — tracking issue

Added the upstream octokit discussion link (https://github.com/octokit/octokit.js/discussions/2050)
directly to the `@ts-expect-error` comment in the code. Will file a tracking issue on this repo as a
follow-up so we have a local TODO to remove the suppression once the upstream types are updated.

tsconfig.test.json — is it needed?

Yes, I believe so since `vitest.config.ts` explicitly references it at `typecheck.tsconfig: './tsconfig.test.json'`.
The separate config excludes `src/app` from type-checking in tests since those files depend on the
Next.js build pipeline (app-router types, `.next/types`) that isn't available in the Vitest context.
Without it, `tsc` would error on app-router imports during `vitest --typecheck`.

Readiness Checklist

Author/Contributor

  • If documentation is needed for this change, has that been included in this pull request
  • run npm run format and fix any formatting issues that have been introduced
  • run npm run lint and fix any linting issues that have been introduced
  • run npm run test and run tests

@Miablo Miablo self-assigned this Jun 15, 2026
@Miablo Miablo changed the title Another miablo octokit chore: upgrade octokit to v5 and probot to v14 Jun 15, 2026
@Miablo Miablo marked this pull request as ready for review June 15, 2026 16:35
@Miablo Miablo requested review from a team as code owners June 15, 2026 16:35
@Miablo

Miablo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

note: this should be run locally to confirm everything is working

Comment thread src/bot/rules.ts

rulesLogger.info('Creating branch protection for all branches', {
repositoryOwner: context.payload.repository.owner.login,
repositoryOwner: context.payload.repository.owner!.login,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to have this handle the case where the repository owner doesn't exist, since the intended result would be the same (log undefined). Otherwise, this could lead to an exception.

Suggested change
repositoryOwner: context.payload.repository.owner!.login,
repositoryOwner: context.payload.repository.owner?.login,

Comment thread src/bot/rules.ts

rulesLogger.info('Creating branch protection for default branch', {
repositoryOwner: context.payload.repository.owner.login,
repositoryOwner: context.payload.repository.owner!.login,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
repositoryOwner: context.payload.repository.owner!.login,
repositoryOwner: context.payload.repository.owner?.login,

Comment thread src/bot/rules.ts
repository: Repository
}>(getBranchProtectionRulesetGQL, {
owner: context.payload.repository.owner.login,
owner: context.payload.repository.owner!.login,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case isn't just logging, so may need better error handling unless we're strongly confident this will always be defined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could potentially make a utility function that handles the value being undefined and reuse that across the uses in the file

Comment thread src/bot/rules.ts
branch: pattern,
enforce_admins: true,
owner: context.payload.repository.owner.login,
owner: context.payload.repository.owner!.login,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Comment thread src/bot/rules.ts
rulesLogger.info('Created branch protection via REST', {
res,
repositoryOwner: context.payload.repository.owner.login,
repositoryOwner: context.payload.repository.owner!.login,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
repositoryOwner: context.payload.repository.owner!.login,
repositoryOwner: context.payload.repository.owner?.login,

Comment thread tsconfig.test.json
@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.json",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is separate tsconfig needed? As part of #435 I updated tsconfig to include tests. Build only needs a separate tsconfig to adjust the default settings, but does test also need that? If not, I would revert this change.

@riley-kohler riley-kohler left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still doing further testing but ran into some initial issues that were causing the application to break that I suggested fixes for.

Comment on lines +38 to 41
// @ts-expect-error getCustomPropertiesValues exists in the API but is not yet
// in octokit 5 type definitions. Tracked upstream:
// https://github.com/octokit/octokit.js/discussions/2050
const props = await octokit.rest.repos.getCustomPropertiesValues({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @ts-expect-error getCustomPropertiesValues exists in the API but is not yet
// in octokit 5 type definitions. Tracked upstream:
// https://github.com/octokit/octokit.js/discussions/2050
const props = await octokit.rest.repos.getCustomPropertiesValues({
const props = await octokit.rest.repos.customPropertiesForReposGetRepositoryValues({

There is a way to get custom properties in Octokit 5 that has types defined it just uses the worst name scheme imaginable.

Comment on lines +181 to 182
// @ts-expect-error getAllCustomProperties exists in the API but is not yet in octokit 5 type definitions
await privateOctokit.rest.orgs.getAllCustomProperties({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @ts-expect-error getAllCustomProperties exists in the API but is not yet in octokit 5 type definitions
await privateOctokit.rest.orgs.getAllCustomProperties({
await privateOctokit.rest.orgs.customPropertiesForReposGetOrganizationDefinitions({

Similar to above but for getting organization custom property definitions.

Comment on lines +192 to 193
// @ts-expect-error createOrUpdateCustomProperty exists in the API but is not yet in octokit 5 type definitions
await privateOctokit.rest.orgs.createOrUpdateCustomProperty({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @ts-expect-error createOrUpdateCustomProperty exists in the API but is not yet in octokit 5 type definitions
await privateOctokit.rest.orgs.createOrUpdateCustomProperty({
await privateOctokit.rest.orgs.customPropertiesForReposCreateOrUpdateOrganizationDefinition({

Similar to above but for setting organization custom property definitions.

Comment thread src/pages/api/webhooks.ts
Comment on lines +15 to 25
export default await createNodeMiddleware(app, {
probot: createProbot({
defaults: {
log: {
child: () => probotLogger,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
},
}),
webhooksPath: '/api/webhooks',
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Probot v14 requires a pino logger so custom logging has been removed
// In the future it is worth considering replacing tslog with pino entirely
export default await createNodeMiddleware(app, {
probot: createProbot(),
webhooksPath: '/api/webhooks',
})

Probot is configured to use Pino and is incompatible with tslog which causes some errors in the new version because Probot started using more features of Pino. This change just removes the custom logging for now which retains most of the functionality but logs will be formatted slightly differently.

Comment thread src/pages/api/webhooks.ts
Comment on lines 2 to 5
import { createNodeMiddleware, createProbot } from 'probot'
import { logger } from 'utils/logger'

export const probot = createProbot()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { createNodeMiddleware, createProbot } from 'probot'
export const probot = createProbot()

The suggestion is behaving a bit strangely but the intent is just to delete the logger import in favor of the change below to use the probot default logging.

Comment thread src/pages/api/webhooks.ts
Comment on lines 5 to 9
export const probot = createProbot()

const probotLogger = logger.getSubLogger({ name: 'probot' })

export const config = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const probot = createProbot()
export const config = {

The suggestion is behaving a bit strangely but the intent is just to delete the sub logger creation in favor of the change below to use the probot default logging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update Octokit to v5

3 participants