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
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 12.x
- run: npm ci
- run: npm run build:schema
- run: npx semantic-release
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ jobs:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
- run: npm ci
- run: npm test
typecheck:
name: test
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 typecheck
6 changes: 3 additions & 3 deletions .github/workflows/update-prettier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
update_prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@v1
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
version: 12
node-version: 12.x
- run: npm ci
- run: "npm run lint:fix"
- uses: gr2m/[email protected]
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 10.x
node-version: 12.x
- run: git checkout webhooks-update || true
- run: npm ci
- run: bin/octokit-webhooks.js update
- run: bin/octokit-webhooks.ts update
- uses: gr2m/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.OCTOKITBOT_PAT }}
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ If you figure out how to fix the issue then please push the fix to the pull requ
The [`index.json` file](https://github.com/octokit/webhooks/blob/master/index.json) is generated, please do not edit it. Instead, make changes in the [`payload-examples/api.github.com/` folder](https://github.com/octokit/webhooks/tree/master/payload-examples/api.github.com), then update `index.json` by running the following command

```
node bin/octokit-webhooks.js update --cached
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.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ import SCHEMA from "@octokit/webhooks-definitions/schema.json";

## 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.js`](bin/octokit-webhooks.js). Run `node bin/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.
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.

The update script is scraping [GitHub’s Webhooks Event Types & Payloads](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads) documentation page and extracts the meta information using [cheerio](https://www.npmjs.com/package/cheerio).

Expand Down
47 changes: 29 additions & 18 deletions bin/octokit-schema.js → bin/octokit-schema.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
const { strict: assert } = require("assert");
const fs = require("fs");
const path = require("path");
const prettier = require("prettier");
const $RefParser = require("@apidevtools/json-schema-ref-parser");
#!/usr/bin/env ts-node-transpile-only

import $RefParser from "@apidevtools/json-schema-ref-parser";
import { strict as assert } from "assert";
import fs from "fs";
import { JSONSchema7 } from "json-schema";
import path from "path";
import { format } from "prettier";

const pathToWebhookSchemas = "payload-schemas/schemas";

const removeExtension = (fileName, ext) => {
const removeExtension = (fileName: string, ext: string): string => {
assert.ok(fileName.endsWith(ext), `"${fileName}" does not end with "${ext}"`);

return fileName.substring(0, fileName.length - ext.length);
};

const buildCommonSchemasDefinitionSchema = () => {
const buildCommonSchemasDefinitionSchema = (): Record<string, JSONSchema7> => {
const commonSchemas = fs.readdirSync(`${pathToWebhookSchemas}/common`);
const definitions = {};
const definitions: Record<string, JSONSchema7> = {};

commonSchemas.forEach((schema) => {
definitions[removeExtension(schema, ".schema.json")] = {
Expand All @@ -35,8 +38,11 @@ const listEvents = () => {
.map((entity) => entity.name);
};

type EventSchema = JSONSchema7 &
Required<Pick<JSONSchema7, "$id" | "oneOf" | "definitions">>;

const combineEventSchemas = () => {
const eventSchema = {
const eventSchema: EventSchema = {
$id: "webhooks",
$schema: "http://json-schema.org/draft-07/schema#",
definitions: {},
Expand All @@ -47,13 +53,14 @@ const combineEventSchemas = () => {

events.forEach((event) => {
const schemas = fs.readdirSync(`${pathToWebhookSchemas}/${event}`);
const eventName = `${event}_event`;

if (schemas.length === 1 && schemas[0] === "event.schema.json") {
// schemas without any actions are just called "event"
const schema = require(`../${pathToWebhookSchemas}/${event}/event.schema.json`);
const schema = require(`../${pathToWebhookSchemas}/${event}/event.schema.json`) as JSONSchema7;
const eventName = schema.$id;

assert.ok(eventName, `${event}/event.schema.json does not have an $id`);

eventSchema.definitions = {
...eventSchema.definitions,
...schema.definitions,
Expand All @@ -64,13 +71,15 @@ const combineEventSchemas = () => {

eventSchema.oneOf.push({ $ref: `#/definitions/${eventName}` });

return eventSchema;
return;
}

const eventActions = schemas.map((schemaName) => {
const schema = require(`../${pathToWebhookSchemas}/${event}/${schemaName}`);
const schema = require(`../${pathToWebhookSchemas}/${event}/${schemaName}`) as JSONSchema7;
const actionEventName = schema.$id;

assert.ok(actionEventName, `${event}/${schemaName} does not have an $id`);

eventSchema.definitions = {
...eventSchema.definitions,
...schema.definitions,
Expand All @@ -82,6 +91,8 @@ const combineEventSchemas = () => {
return actionEventName;
});

const eventName = `${event}_event`;

eventSchema.definitions = {
...eventSchema.definitions,
[eventName]: {
Expand All @@ -99,10 +110,10 @@ const combineEventSchemas = () => {

async function run() {
try {
const schema = combineEventSchemas();
const commonSchemaDefinitions = await $RefParser.dereference(
const schema: EventSchema = combineEventSchemas();
const commonSchemaDefinitions = (await $RefParser.dereference(
buildCommonSchemasDefinitionSchema()
);
)) as Record<string, JSONSchema7>;

schema.definitions = {
...schema.definitions,
Expand All @@ -111,8 +122,8 @@ async function run() {

fs.writeFileSync(
"schema.json",
prettier.format(
JSON.stringify(schema, (key, value) => {
format(
JSON.stringify(schema, (key, value: unknown) => {
if (
typeof value === "string" &&
value.startsWith("common/") &&
Expand Down
22 changes: 14 additions & 8 deletions bin/octokit-webhooks.js → bin/octokit-webhooks.ts
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#!/usr/bin/env node
#!/usr/bin/env ts-node-transpile-only

const checkOrUpdateWebhooks = require("../lib/check-or-update-webhooks");
import yargs from "yargs";
import { checkOrUpdateWebhooks } from "../lib";

interface Options {
cached: boolean;
}

const {
cached,
_: [command],
} = require("yargs")
} = yargs
.command("update", "Update webhooks", (yargs) => {
yargs
.options({
Expand All @@ -15,7 +20,7 @@ const {
default: false,
},
})
.example("$0 update --cached");
.example("$0 update --cached", "");
})
.command("check", "Check if webhooks are up-to-date", (yargs) => {
yargs
Expand All @@ -26,20 +31,21 @@ const {
default: false,
},
})
.example("$0 check --cached");
.example("$0 check --cached", "");
})
.help("h")
.alias("h", ["help", "usage"])
.demandCommand(1, "")
.usage("bin/octokit-webhooks.js <command> [--cached]").argv;
.scriptName("bin/octokit-webhooks")
.usage("$0 <command> [--cached]").argv as yargs.Arguments<Options>;

if (!["update", "check"].includes(command)) {
if (!["update", "check"].includes(command.toString())) {
console.log(`"${command}" must be one of: update, check`);
process.exit(1);
}

checkOrUpdateWebhooks({ cached, checkOnly: command === "check" }).catch(
(error) => {
(error: Error) => {
console.log(error.stack);
process.exit(1);
}
Expand Down
12 changes: 6 additions & 6 deletions bin/validate-payload-examples.js → bin/validate-payload-examples.ts
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#!/usr/bin/env node
#!/usr/bin/env ts-node-transpile-only

const fs = require("fs");
const { ajv, validate } = require("../payload-schemas");
const { MissingRefError } = require("ajv/dist/compile/error_classes");
import fs from "fs";
import { ajv, validate } from "../payload-schemas";

let hasErrors = false;
let hasErrors = false as boolean;
const payloads = `./payload-examples/api.github.com`;

fs.readdirSync(payloads).forEach((event) => {
fs.readdirSync(`${payloads}/${event}`)
.filter((filename) => filename.endsWith(".json"))
.forEach((filename) => {
const file = require(`../${payloads}/${event}/${filename}`);
const file = require(`../${payloads}/${event}/${filename}`) as unknown;

try {
const validationResult = validate(event, file);

if (!validationResult) {
console.error(
`❌ Payload '${event}/${filename}' does not match schema`
Expand Down
6 changes: 3 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
type WebhookExample = {
[key: string]: any
}
[key: string]: any;
};
export type WebhookDefinition = {
name: string;
actions: string[];
examples: WebhookExample[];
}
};
39 changes: 0 additions & 39 deletions lib/cache.js

This file was deleted.

19 changes: 19 additions & 0 deletions lib/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { promises as fs } from "fs";
import { dirname, resolve as resolvePath } from "path";

const CACHE_DIR = resolvePath(__dirname, "..", "cache");

const toCachePath = (path: string) => resolvePath(CACHE_DIR, `./${path}`);

export const cache = {
async read(path: string): Promise<string> {
return fs.readFile(toCachePath(path), "utf8");
},
async write(path: string, data: string): Promise<void> {
const cachePath = toCachePath(path);

await fs.mkdir(dirname(cachePath), { recursive: true });

return fs.writeFile(cachePath, data);
},
};
Loading