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
30 changes: 30 additions & 0 deletions .github/workflows/live-ghost-content-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Live Ghost content smoke

on:
workflow_dispatch:

permissions:
contents: read

jobs:
smoke:
name: Observe live Ghost content
if: github.repository == 'TryGhost/algolia' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run live content smoke
env:
GHOST_URL: https://main.ghost.is
GHOST_API_VERSION: v6.0
MAIN_GHOST_CONTENT_API_KEY: ${{ secrets.MAIN_GHOST_CONTENT_API_KEY }}
run: pnpm --filter @tryghost/algolia-html-extractor smoke:live
16 changes: 16 additions & 0 deletions packages/algolia-html-extractor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,19 @@ position, its heading rank, and the source tag. The returned values are read-onl
The package handles HTML parsing itself and has no configuration options. Turning fragments into
Algolia records, merging `pre` content, and sending records to Algolia are separate jobs handled by
the downstream packages.

## Maintainer smoke check

Maintainers can run the `Live Ghost content smoke` workflow by hand to check published posts and
pages from `main.ghost.is`. It runs only from this repository's `main` branch and writes a
privacy-safe structural summary to the job. It does not save live content, write a baseline, run on
pull requests, or publish the package.

The workflow installs the workspace and then runs:

```sh
pnpm --filter @tryghost/algolia-html-extractor smoke:live
```

This command expects the workflow's URL, API version, Content API key, and job-summary environment.
It is not a general-purpose extractor command.
1 change: 1 addition & 0 deletions packages/algolia-html-extractor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"lint": "oxlint --quiet . && oxfmt --check .",
"posttest": "pnpm typecheck && pnpm lint",
"build": "tsc --project tsconfig.build.json",
"smoke:live": "node smoke/cli.mts",
"prepack": "pnpm build"
},
"files": [
Expand Down
70 changes: 70 additions & 0 deletions packages/algolia-html-extractor/smoke/cli.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {appendFile} from 'node:fs/promises';

import {
SmokeError,
runLiveGhostContentSmoke,
type SmokeTransport,
type SmokeTransportRequest
} from './live-ghost-content-smoke.mts';

const REQUEST_TIMEOUT_MS = 30_000;

const createRequestUrl = (request: SmokeTransportRequest): URL => {
const requestUrl = new URL(`/ghost/api/content/${request.contentType}/`, request.target);
requestUrl.searchParams.set('key', request.contentApiKey);
requestUrl.searchParams.set('fields', request.fields);
requestUrl.searchParams.set('formats', request.formats);
requestUrl.searchParams.set('limit', String(request.limit));
requestUrl.searchParams.set('page', String(request.page));
return requestUrl;
};

const transport: SmokeTransport = async request => {
const response = await fetch(createRequestUrl(request), {
method: 'GET',
headers: {'Accept-Version': request.apiVersion},
redirect: request.redirect,
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
});

let body: unknown = null;
if (response.status >= 200 && response.status < 300) {
try {
body = await response.json();
} catch {
body = null;
}
}

return {
status: response.status,
redirected: response.redirected,
body
};
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const summaryPath = process.env.GITHUB_STEP_SUMMARY;
if (summaryPath === undefined || summaryPath === '') {
process.stderr.write('Live Ghost content smoke failed: operational-failure\n');
process.exitCode = 1;
} else {
try {
const report = await runLiveGhostContentSmoke({
target: process.env.GHOST_URL ?? '',
apiVersion: process.env.GHOST_API_VERSION ?? '',
contentApiKey: process.env.MAIN_GHOST_CONTENT_API_KEY ?? '',
transport,
clock: () => new Date(),
summarySink: summary => appendFile(summaryPath, summary, 'utf8')
});

process.stdout.write(`Live Ghost content smoke: ${report.category}\n`);
if (report.category !== 'ok') {
process.exitCode = 1;
}
} catch (error) {
const category = error instanceof SmokeError ? error.category : 'operational-failure';
process.stderr.write(`Live Ghost content smoke failed: ${category}\n`);
process.exitCode = 1;
}
}
Loading