Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,18 @@ jobs:
node-version: 12.x
- run: npm ci
- run: npm run typecheck
do-types-need-regenerating:
name: Do types need to be regenerated?
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
- run: npm ci
- run: npm run build:schema
- run: npm run build:types
- run: git status
- run: |
git diff --exit-code || bash -c \
'echo "::error file=schema.d.ts::This needs to be regenerated by running \`build:types\`" && false'
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ npm run build:webhooks -- --cached

When you send a pull request, make sure that the `index.json` file is up-to-date with the changes in the `payload-examples/api.github.com/` folder, otherwise the tests will fail.

## Updating types

The [`schema.d.ts` file](https://github.com/octokit/webhooks/blob/master/schema.d.ts) is generated, please do not edit it.
Instead, make changes to the schemas in the [`payload-schemas/schemas/` folder](https://github.com/octokit/webhooks/tree/master/payload-schemas/schemas), then generate the schema and update the types with the following commands:

```shell
npm run build:schema
npm run build:types
```

## Merging the Pull Request & releasing a new version

Releases are automated using [semantic-release](https://github.com/semantic-release/semantic-release).
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,20 @@ const SCHEMA = require("@octokit/webhooks-definitions/schema.json");
import SCHEMA from "@octokit/webhooks-definitions/schema.json";
```

## Importing types

This package ships with types for the webhook events generated from the respective json schemas, which you can use like so:

```typescript
import { IssuesOpenedEvent } from "@octokit/webhooks-definitions/schema";

const handleIssuesOpenedEvent = (event: IssuesOpenedEvent) => {
console.log(
`${event.sender.login} opened "${event.issue.title}" on ${event.repository.full_name}`
);
};
```

## How it works

This package updates itself using a daily cronjob running on GitHub Actions. The [`index.json`](index.json) file is generated by [`bin/octokit-webhooks.ts`](bin/octokit-webhooks.ts). Run `npm run octokit-webhooks -- --usage` for instructions. After the update is complete, run `npm run build:webhooks` and `npm run build:schema` to update `index.json` and `schema.json` files.
Expand Down
67 changes: 67 additions & 0 deletions bin/octokit-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env ts-node-transpile-only

import { strict as assert } from "assert";
import { promises as fs } from "fs";
import { JSONSchema7 } from "json-schema";
import { compileFromFile } from "json-schema-to-typescript";
import { format } from "prettier";

const titleCase = (str: string) => `${str[0].toUpperCase()}${str.substring(1)}`;

const guessAtInterfaceName = (str: string) =>
str.split("_").map(titleCase).join("");

const getEventName = (ref: string): string => {
assert.ok(
ref.startsWith("#/definitions/"),
`${ref} does not point to definitions`
);

assert.ok(
ref.endsWith("event"),
`${ref} does not point to an event definition`
);

const [, eventName] = /^#\/definitions\/(.+)[$_]event$/u.exec(ref) ?? [];

assert.ok(eventName, `unable to find an event name from ${ref}`);

return eventName;
};

interface Schema extends JSONSchema7 {
oneOf: Array<JSONSchema7 & Required<Pick<JSONSchema7, "$ref">>>;
}

const buildEventPayloadMap = (schema: Schema): string => {
const properties = schema.oneOf.map(({ $ref }) => {
const eventName = getEventName($ref);
const interfaceName = guessAtInterfaceName(`${eventName}_event`);

return `"${eventName}": ${interfaceName}`;
});

return ["export interface EventPayloadMap {", ...properties, "}"].join("\n");
};

const addEventPayloadMap = (ts: string, schema: Schema): string => {
const payloadMap = buildEventPayloadMap(schema);

return `${ts}${payloadMap}`;
};

const getSchema = async () =>
JSON.parse(await fs.readFile("./schema.json", "utf-8")) as Schema;

const run = async () => {
const schema = await getSchema();

const ts = addEventPayloadMap(
await compileFromFile("./schema.json", { format: false }),
schema
);

await fs.writeFile("./schema.d.ts", format(ts, { parser: "typescript" }));
};

run();
Loading