Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Incidents on Rule Failure #947

Closed
wants to merge 16 commits into from
4 changes: 2 additions & 2 deletions .github/workflows/healthcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_call:
workflow_dispatch:
schedule:
- cron: 1 */6 * * *
- cron: "*/10 * * * *"

env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
Expand All @@ -29,4 +29,4 @@ jobs:

- name: Run Healthchecks
run: |
node packages/healthchecks/dist/cli.cjs docs run
node packages/healthchecks/dist/cli.cjs docs run --generateIncident true
16 changes: 16 additions & 0 deletions fern/apis/incident/generators.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
api:
- path: ./openapi/swagger.json
overrides: ./openapi/overrides.yml
default-group: sdk
groups:
sdk:
generators:
- name: fernapi/fern-typescript-node-sdk
version: 0.9.5
output:
location: npm
url: npm.buildwithfern.com
package-name: "@fern-fern/incident"
config:
skipResponseValidation: true
namespaceExport: Incident
5 changes: 5 additions & 0 deletions fern/apis/incident/openapi/overrides.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
30,615 changes: 30,615 additions & 0 deletions fern/apis/incident/openapi/swagger.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/healthchecks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"devDependencies": {
"@fern-api/fdr-sdk": "workspace:*",
"@fern-fern/vercel": "0.0.7",
"@fern-fern/incident": "0.0.3407",
"@types/jest": "^29.5.11",
"@types/node": "^18.7.18",
"@types/yargs": "^17.0.32",
Expand Down
34 changes: 20 additions & 14 deletions packages/healthchecks/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint-disable no-console */
import { hideBin } from "yargs/helpers";
import yargs from "yargs/yargs";
import { createFailedDocLoadIncident } from "./createIncident";
import { getAllFernDocsWebsites } from "./getDocsURLs";
import { runRules } from "./rules/runRules";
import { RuleResult, runRules } from "./rules/runRules";

void yargs(hideBin(process.argv))
.scriptName(process.env.CLI_NAME ?? "fern-healthchecks")
Expand All @@ -20,23 +21,28 @@ void yargs(hideBin(process.argv))
string: true,
default: false,
requred: true,
})
.option("generateIncident", {
boolean: true,
default: false,
}),
async (argv) => {
const urls = argv.url != null ? [argv.url] : await getAllFernDocsWebsites();
let failure = false;
for (const url of urls) {
console.log(`Running rules for ${url}...`);
const results = await runRules({ url });
for (const result of results) {
if (result.success) {
console.log(`:white_check_mark: Rule ${result.name} passed`);
} else {
failure = true;
console.log(`:redx: Rule ${result.name} failed. ${result.message}`);
}
}
const promiseResults: Promise<RuleResult[]>[] = [];
urls.forEach((url) => {
promiseResults.push(runRules({ url }));
});
const results: RuleResult[] = (await Promise.all(promiseResults)).flat();
console.log(`Successful Rules: ${results.filter((result) => result.success).length}`);
const failedResults: RuleResult[] = results.filter((result) => !result.success);
console.log(`Failed Rules: ${failedResults.length}`);
if (failedResults.length && argv.generateIncident) {
const incidentResponse = await createFailedDocLoadIncident(failedResults);
console.log(
`Generated incident ${incidentResponse.incident.reference}. Access here ${incidentResponse.incident.permalink}`,
);
}
process.exit(failure ? 1 : 0);
process.exit(failedResults.length ? 1 : 0);
},
)
.demandCommand()
Expand Down
26 changes: 26 additions & 0 deletions packages/healthchecks/src/createIncident.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IncidentClient } from "@fern-fern/incident";
import { ShowResponseBody13 } from "@fern-fern/incident/api";
import { RuleResult } from "./rules/runRules";

const INCIDENT = new IncidentClient({
token: process.env.INCIDENT_TOKEN ?? "",
});

/**
* Generates an incident and returns the response
*/
export async function createFailedDocLoadIncident(failedResults: RuleResult[]): Promise<ShowResponseBody13> {
return await INCIDENT.incidentsV2.create({
id: `${Date.now()} fern-platform-health-check-failure`,
idempotencyKey: "fern-platform-health-check-failure",
mode: "standard",
name: "fern platform health checks have failed",
summary: `These are the health checks that failed: ${failedResults.map((result) => formatResult(result)).flat()}`,
severityId: "01HR85VFNXA1RTYRR744G9FN6J",
visibility: "public",
});
}

function formatResult(result: RuleResult): string {
return `rule ${result.name} for url ${result.url} ${result.success ? "succeeded" : "failed"} -- ${result.message}`;
}
7 changes: 4 additions & 3 deletions packages/healthchecks/src/rules/all-pages-load/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ export class AllPagesLoadRule implements Rule {
name: this.name,
success: false,
message: `Failed to load docs for ${url} from FDR`,
url,
};
}
const node = FernNavigation.utils.convertLoadDocsForUrlResponse(getDocsForUrlResponse.body);
const slugCollector = NodeCollector.collect(node);
const urls = slugCollector
.getPageSlugs()
.map((slug) => `${getDocsForUrlResponse.body.baseUrl.domain}/ ${slug}`);
const urls = slugCollector.getPageSlugs().map((slug) => `${getDocsForUrlResponse.body.baseUrl.domain}/${slug}`);

const responses = await Promise.all(
urls.map(async (url) => {
Expand All @@ -39,13 +38,15 @@ export class AllPagesLoadRule implements Rule {
name: this.name,
success: false,
message: `The following URLs do not load: ${failedURLs.join(", ")}`,
url,
};
}

return {
name: this.name,
success: true,
message: "All URLs are reachable",
url,
};
}
}
1 change: 1 addition & 0 deletions packages/healthchecks/src/rules/runRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface RuleResult {
name: string;
success: boolean;
message: string;
url: string;
}

function getAllRules(): Rule[] {
Expand Down
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading