Skip to content

Add managed OAuth MCP integrations for HubSpot #215

Add managed OAuth MCP integrations for HubSpot

Add managed OAuth MCP integrations for HubSpot #215

Workflow file for this run

name: Docs
on:
pull_request:
paths:
- "docs/**"
- ".github/workflows/docs.yml"
push:
branches: [main]
paths:
- "docs/**"
- ".github/workflows/docs.yml"
workflow_dispatch: {}
concurrency:
group: docs-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
packages: write
pull-requests: read
env:
DOCS_SITE_URL: https://docs.gobii.ai
DOCS_IMAGE: ghcr.io/gobii-ai/gobii-docs
jobs:
preview_preflight:
name: Resolve Docs Preview Inputs
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
outputs:
docs_changed: ${{ steps.resolve.outputs.docs_changed }}
head_sha: ${{ steps.resolve.outputs.head_sha }}
short_sha: ${{ steps.resolve.outputs.short_sha }}
preview_url: ${{ steps.resolve.outputs.preview_url }}
steps:
- name: Resolve PR docs changes
id: resolve
uses: actions/github-script@v8
with:
script: |
const pr = context.payload.pull_request;
if (!pr) {
throw new Error('pull_request payload missing.');
}
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
per_page: 100,
});
const docsChanged = files.some((file) => file.filename.startsWith('docs/'));
const headSha = pr.head.sha;
core.setOutput('docs_changed', String(docsChanged));
core.setOutput('head_sha', headSha);
core.setOutput('short_sha', headSha.substring(0, 7));
core.setOutput('preview_url', `https://docs-pr-${pr.number}.ship.gobii.ai`);
build:
name: Build Docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: "22"
cache: npm
cache-dependency-path: docs/package-lock.json
- name: Install dependencies
working-directory: docs
run: npm ci
- name: Verify analytics secret
if: github.event_name != 'pull_request'
env:
DOCS_GTAG_TRACKING_ID: ${{ secrets.DOCS_GTAG_TRACKING_ID }}
run: |
set -euo pipefail
if [ -z "${DOCS_GTAG_TRACKING_ID:-}" ]; then
echo "DOCS_GTAG_TRACKING_ID must be configured on gobii-ai/gobii-platform for production docs builds." >&2
exit 1
fi
- name: Build static docs
working-directory: docs
env:
DOCS_GTAG_TRACKING_ID: ${{ secrets.DOCS_GTAG_TRACKING_ID }}
run: npm run build
- name: Verify analytics tag when configured
working-directory: docs
env:
DOCS_GTAG_TRACKING_ID: ${{ secrets.DOCS_GTAG_TRACKING_ID }}
run: |
set -euo pipefail
if [ -n "${DOCS_GTAG_TRACKING_ID:-}" ]; then
grep -q 'googletagmanager.com/gtag/js?id=' build/index.html
fi
- name: Verify required routes
working-directory: docs
run: |
set -euo pipefail
required=(
build/index.html
build/getting-started/introduction.html
build/developers/developer-basics.html
build/api-reference/gobii-api.html
build/api-reference/list-persistent-agents.html
build/api-reference/agents-api/get-agents.html
build/api-reference/agents-api/get-agents.md
build/GobiiAPI.yaml
build/openapi/GobiiAPI.yaml
build/legacy-redirects.conf
build/api-reference/openapi.json
build/llms.txt
build/llms-full.txt
build/pagefind/pagefind-ui.js
)
for file in "${required[@]}"; do
test -s "$file"
done
- name: Verify nginx routing
working-directory: docs
env:
DOCS_GTAG_TRACKING_ID: ${{ secrets.DOCS_GTAG_TRACKING_ID }}
run: |
set -euo pipefail
image="gobii-docs-ci:${GITHUB_SHA}"
container="gobii-docs-ci-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
docker build \
--build-arg DOCS_SITE_URL="${DOCS_SITE_URL}" \
--build-arg DOCS_GTAG_TRACKING_ID="${DOCS_GTAG_TRACKING_ID}" \
-t "$image" .
docker run -d --rm --name "$container" -p 8080:8080 "$image"
trap 'docker rm -f "$container" >/dev/null 2>&1 || true' EXIT
ready=0
for _ in {1..20}; do
if curl -fsS http://127.0.0.1:8080/healthz >/dev/null 2>&1; then
ready=1
break
fi
sleep 1
done
test "$ready" = "1"
code_for() {
curl -sS -o /dev/null -w '%{http_code}' "http://127.0.0.1:8080$1"
}
redirect_for() {
curl -sS -o /dev/null -w '%{http_code} %{redirect_url}' "http://127.0.0.1:8080$1"
}
test "$(code_for /)" = "200"
test "$(code_for /healthz)" = "200"
if [ -n "${DOCS_GTAG_TRACKING_ID:-}" ]; then
curl -fsS http://127.0.0.1:8080/ | grep -q 'googletagmanager.com/gtag/js?id='
fi
test "$(code_for /api-reference/gobii-api)" = "200"
test "$(code_for /api-reference/list-persistent-agents)" = "200"
test "$(redirect_for /index.html)" = "301 http://127.0.0.1:8080/"
test "$(redirect_for /api-reference)" = "301 http://127.0.0.1:8080/api-reference/gobii-api"
test "$(redirect_for /api-reference/agents-api/get-agents)" = "301 http://127.0.0.1:8080/api-reference/list-persistent-agents"
test "$(redirect_for '/api-reference/agents-api/get-agents?utm_source=x')" = "301 http://127.0.0.1:8080/api-reference/list-persistent-agents?utm_source=x"
test "$(redirect_for /api-reference/agents-api/get-agents.html)" = "301 http://127.0.0.1:8080/api-reference/list-persistent-agents"
test "$(redirect_for /getting-started/introduction)" = "301 http://127.0.0.1:8080/"
test "$(redirect_for /getting-started/introduction.html)" = "301 http://127.0.0.1:8080/"
test "$(redirect_for /getting-started/introduction/)" = "301 http://127.0.0.1:8080/"
test "$(redirect_for /core-concepts)" = "301 http://127.0.0.1:8080/start-here/core-concepts"
test "$(redirect_for /core-concepts.html)" = "301 http://127.0.0.1:8080/start-here/core-concepts"
test "$(redirect_for /core-concepts/)" = "301 http://127.0.0.1:8080/start-here/core-concepts"
test "$(redirect_for /console-guides)" = "301 http://127.0.0.1:8080/using-gobii"
test "$(redirect_for /console-guides.html)" = "301 http://127.0.0.1:8080/using-gobii"
test "$(redirect_for /console-guides/)" = "301 http://127.0.0.1:8080/using-gobii"
test "$(redirect_for /console-guides/live-chat-guide)" = "301 http://127.0.0.1:8080/using-gobii/chat-and-timeline"
test "$(redirect_for /console-guides/live-chat-guide.html)" = "301 http://127.0.0.1:8080/using-gobii/chat-and-timeline"
test "$(redirect_for /console-guides/live-chat-guide/)" = "301 http://127.0.0.1:8080/using-gobii/chat-and-timeline"
test "$(redirect_for /console-guides/meta-gobii)" = "301 http://127.0.0.1:8080/using-gobii/meta-gobii"
test "$(redirect_for /console-guides/meta-gobii.html)" = "301 http://127.0.0.1:8080/using-gobii/meta-gobii"
test "$(redirect_for /console-guides/meta-gobii/)" = "301 http://127.0.0.1:8080/using-gobii/meta-gobii"
test "$(code_for /using-gobii/meta-gobii)" = "200"
test "$(code_for /definitely-not-a-real-docs-url)" = "404"
test "$(redirect_for /definitely-not-a-real-docs-url/)" = "301 http://127.0.0.1:8080/definitely-not-a-real-docs-url"
test "$(code_for /404)" = "404"
test "$(code_for /404.html)" = "404"
header_for() {
local path="$1"
local header="$2"
curl -sSI "http://127.0.0.1:8080${path}" \
| awk -v header="${header}" 'BEGIN { IGNORECASE = 1 } index($0, header ":") == 1 { sub("\r$", ""); sub("^[^:]+: *", ""); print; exit }'
}
asset_js="$(node - <<'NODE'
(async () => {
const html = await (await fetch('http://127.0.0.1:8080/')).text();
const match = html.match(/\/assets\/js\/[^"]+\.js/);
if (!match) process.exit(1);
console.log(match[0]);
})();
NODE
)"
pagefind_fragment="/$(find build/pagefind/fragment -name '*.pf_fragment' -print -quit | sed 's#^build/##')"
test "$(header_for /healthz Cache-Control)" = "no-store"
test "$(header_for / Cache-Control)" = "public, max-age=0, must-revalidate"
test "$(header_for / CDN-Cache-Control)" = "public, max-age=300, stale-while-revalidate=86400"
test "$(header_for / Cloudflare-CDN-Cache-Control)" = "public, max-age=300, stale-while-revalidate=86400"
test "$(header_for "$asset_js" Cache-Control)" = "public, max-age=31536000, immutable"
test "$(header_for /assets/js/not-real.js Cache-Control)" = ""
test "$(header_for /pagefind/pagefind-ui.js Cache-Control)" = "public, max-age=300, must-revalidate"
test "$(header_for "$pagefind_fragment" Cache-Control)" = "public, max-age=31536000, immutable"
test "$(header_for /api-reference/openapi.json Cloudflare-CDN-Cache-Control)" = "public, max-age=300, stale-while-revalidate=86400"
test "$(header_for /api-reference/openapi.json X-Robots-Tag)" = "noindex"
test "$(header_for /developers.md Cache-Control)" = "public, max-age=300, must-revalidate"
test "$(header_for /developers.md X-Robots-Tag)" = "noindex"
test "$(header_for /llms.txt X-Robots-Tag)" = "noindex"
test "$(header_for /llms-full.txt X-Robots-Tag)" = "noindex"
test "$(header_for /GobiiAPI.yaml X-Robots-Tag)" = "noindex"
test "$(header_for /openapi/GobiiAPI.yaml X-Robots-Tag)" = "noindex"
test "$(header_for / X-Robots-Tag)" = ""
test "$(header_for /api-reference/list-persistent-agents X-Robots-Tag)" = ""
test "$(header_for /api-reference/agents-api/get-agents Cache-Control)" = "public, max-age=300"
publish:
name: Publish Docs Image
runs-on: ubuntu-latest
needs: [build]
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
outputs:
short_sha: ${{ steps.meta.outputs.short_sha }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Resolve image metadata
id: meta
run: |
short_sha="${GITHUB_SHA::7}"
echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push docs image
uses: docker/build-push-action@v7
with:
context: docs
file: docs/Dockerfile
push: true
tags: |
${{ env.DOCS_IMAGE }}:sha-${{ github.sha }}
${{ env.DOCS_IMAGE }}:sha-${{ steps.meta.outputs.short_sha }}
${{ env.DOCS_IMAGE }}:staging
labels: |
org.opencontainers.image.revision=${{ github.sha }}
build-args: |
DOCS_SITE_URL=${{ env.DOCS_SITE_URL }}
DOCS_GTAG_TRACKING_ID=${{ secrets.DOCS_GTAG_TRACKING_ID }}
cache-from: type=gha,scope=gobii-docs
cache-to: type=gha,mode=max,scope=gobii-docs
platforms: linux/amd64
provenance: false
sbom: false
publish_preview:
name: Publish Docs Preview Image
runs-on: ubuntu-latest
needs: [build, preview_preflight]
if: >
github.event_name == 'pull_request' &&
needs.preview_preflight.outputs.docs_changed == 'true' &&
github.event.pull_request.head.repo.full_name == github.repository
outputs:
image: ${{ steps.meta.outputs.image }}
steps:
- name: Checkout PR head
uses: actions/checkout@v6
with:
ref: ${{ needs.preview_preflight.outputs.head_sha }}
- name: Resolve image metadata
id: meta
env:
HEAD_SHA: ${{ needs.preview_preflight.outputs.head_sha }}
run: |
set -euo pipefail
echo "image=${DOCS_IMAGE}:sha-${HEAD_SHA}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push docs preview image
uses: docker/build-push-action@v7
with:
context: docs
file: docs/Dockerfile
push: true
tags: |
${{ env.DOCS_IMAGE }}:sha-${{ needs.preview_preflight.outputs.head_sha }}
${{ env.DOCS_IMAGE }}:pr-${{ github.event.pull_request.number }}
labels: |
org.opencontainers.image.revision=${{ needs.preview_preflight.outputs.head_sha }}
build-args: |
DOCS_SITE_URL=${{ needs.preview_preflight.outputs.preview_url }}
cache-from: type=gha,scope=gobii-docs
cache-to: type=gha,mode=max,scope=gobii-docs
platforms: linux/amd64
provenance: false
sbom: false
deploy_preview:
name: Dispatch Docs Preview Deployment
runs-on: ubuntu-latest
needs: [preview_preflight, publish_preview]
if: >
github.event_name == 'pull_request' &&
needs.preview_preflight.outputs.docs_changed == 'true' &&
github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: gobii-ai
repositories: gobii
- name: Notify infra repo
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ steps.app-token.outputs.token }}
repository: gobii-ai/gobii
event-type: docs-preview-ready
client-payload: |
{
"owner": "${{ github.repository_owner }}",
"repo": "${{ github.event.repository.name }}",
"pr_number": ${{ github.event.pull_request.number }},
"head_sha": "${{ needs.preview_preflight.outputs.head_sha }}",
"image": "${{ needs.publish_preview.outputs.image }}",
"html_url": "${{ github.event.pull_request.html_url }}",
"trigger_run_id": ${{ github.run_id }},
"trigger_run_attempt": ${{ github.run_attempt }},
"actor": "${{ github.actor }}"
}
deploy:
name: Dispatch Docs Staging Deployment
runs-on: ubuntu-latest
needs: [publish]
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: gobii-ai
repositories: gobii
- name: Notify infra repo
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ steps.app-token.outputs.token }}
repository: gobii-ai/gobii
event-type: docs-staging-ready
client-payload: |
{
"owner": "${{ github.repository_owner }}",
"repo": "${{ github.event.repository.name }}",
"ref": "${{ github.ref }}",
"head_sha": "${{ github.sha }}",
"short_sha": "${{ needs.publish.outputs.short_sha }}",
"image": "${{ env.DOCS_IMAGE }}:sha-${{ github.sha }}",
"trigger_run_id": ${{ github.run_id }},
"trigger_run_attempt": ${{ github.run_attempt }},
"actor": "${{ github.actor }}"
}