Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee7377f6df |
@@ -1,58 +0,0 @@
|
|||||||
# Validate and publish OpenAPI specs to RapidAPI when apis/*/openapi.yaml changes on main.
|
|
||||||
# Requires secrets (configured once RapidAPI listings are live):
|
|
||||||
# RAPIDAPI_PLATFORM_KEY, RAPIDAPI_ZIP_API_ID, RAPIDAPI_ZIP_VERSION_ID,
|
|
||||||
# RAPIDAPI_HOLIDAYS_API_ID, RAPIDAPI_HOLIDAYS_VERSION_ID,
|
|
||||||
# RAPIDAPI_AQI_API_ID, RAPIDAPI_AQI_VERSION_ID
|
|
||||||
#
|
|
||||||
# If RAPIDAPI_PLATFORM_KEY is not set the publish step exits 0 with a skip message.
|
|
||||||
|
|
||||||
name: Validate and Publish OpenAPI Specs
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- 'apis/*/openapi.yaml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
name: Lint and publish specs
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout (with history for diff)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
- name: Set up Node.js 20
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Install Redocly CLI
|
|
||||||
run: npm install -g @redocly/cli@latest
|
|
||||||
|
|
||||||
- name: Lint OpenAPI specs
|
|
||||||
run: |
|
|
||||||
echo "Linting all OpenAPI specs..."
|
|
||||||
npx @redocly/cli lint apis/*/openapi.yaml
|
|
||||||
|
|
||||||
- name: Detect changed specs
|
|
||||||
id: changed
|
|
||||||
run: |
|
|
||||||
changed=$(git diff --name-only HEAD~1 HEAD | grep 'openapi\.yaml' || true)
|
|
||||||
echo "Changed specs: ${changed:-none}"
|
|
||||||
echo "files=${changed}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Publish specs to RapidAPI
|
|
||||||
env:
|
|
||||||
RAPIDAPI_KEY: ${{ secrets.RAPIDAPI_PLATFORM_KEY }}
|
|
||||||
RAPIDAPI_ZIP_API_ID: ${{ secrets.RAPIDAPI_ZIP_API_ID }}
|
|
||||||
RAPIDAPI_ZIP_VERSION_ID: ${{ secrets.RAPIDAPI_ZIP_VERSION_ID }}
|
|
||||||
RAPIDAPI_HOLIDAYS_API_ID: ${{ secrets.RAPIDAPI_HOLIDAYS_API_ID }}
|
|
||||||
RAPIDAPI_HOLIDAYS_VERSION_ID: ${{ secrets.RAPIDAPI_HOLIDAYS_VERSION_ID }}
|
|
||||||
RAPIDAPI_AQI_API_ID: ${{ secrets.RAPIDAPI_AQI_API_ID }}
|
|
||||||
RAPIDAPI_AQI_VERSION_ID: ${{ secrets.RAPIDAPI_AQI_VERSION_ID }}
|
|
||||||
run: node scripts/publish-openapi.js
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
# This manifest is FOR REFERENCE — the live version must be committed to
|
# This manifest is FOR REFERENCE — the live version must be committed to
|
||||||
# 0xWheatyz/Talos at testing1/first-cluster/cluster/flux/api-company-source/
|
# 0xWheatyz/Talos at testing1/first-cluster/cluster/flux/api-company/
|
||||||
#
|
#
|
||||||
# See leeworks-agents/api-company#2
|
# See leeworks-agents/api-company#2
|
||||||
# See leeworks-agents/api-company#97
|
|
||||||
|
|
||||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
@@ -18,8 +17,3 @@ spec:
|
|||||||
prune: true
|
prune: true
|
||||||
wait: true
|
wait: true
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
postBuild:
|
|
||||||
substituteFrom:
|
|
||||||
- kind: Secret
|
|
||||||
name: grafana-admin
|
|
||||||
optional: false
|
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/**
|
|
||||||
* publish-openapi.js
|
|
||||||
*
|
|
||||||
* Uploads each API's openapi.yaml to the RapidAPI Platform API.
|
|
||||||
* Environment variables required per API (skips silently if not set):
|
|
||||||
* RAPIDAPI_KEY — RapidAPI Platform API bearer token
|
|
||||||
* RAPIDAPI_ZIP_API_ID — API ID for ZIP Enrichment on RapidAPI
|
|
||||||
* RAPIDAPI_ZIP_VERSION_ID — Version ID for ZIP Enrichment
|
|
||||||
* RAPIDAPI_HOLIDAYS_API_ID
|
|
||||||
* RAPIDAPI_HOLIDAYS_VERSION_ID
|
|
||||||
* RAPIDAPI_AQI_API_ID
|
|
||||||
* RAPIDAPI_AQI_VERSION_ID
|
|
||||||
*
|
|
||||||
* Usage: node scripts/publish-openapi.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const https = require('https');
|
|
||||||
|
|
||||||
const RAPIDAPI_KEY = process.env.RAPIDAPI_KEY || process.env.RAPIDAPI_PLATFORM_KEY;
|
|
||||||
|
|
||||||
if (!RAPIDAPI_KEY) {
|
|
||||||
console.log('⚠️ RAPIDAPI_KEY / RAPIDAPI_PLATFORM_KEY not set — skipping all spec uploads.');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const APIS = [
|
|
||||||
{
|
|
||||||
name: 'zip-enrichment',
|
|
||||||
specPath: path.join(__dirname, '..', 'apis', 'zip-enrichment', 'openapi.yaml'),
|
|
||||||
apiId: process.env.RAPIDAPI_ZIP_API_ID,
|
|
||||||
versionId: process.env.RAPIDAPI_ZIP_VERSION_ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'holidays',
|
|
||||||
specPath: path.join(__dirname, '..', 'apis', 'holidays', 'openapi.yaml'),
|
|
||||||
apiId: process.env.RAPIDAPI_HOLIDAYS_API_ID,
|
|
||||||
versionId: process.env.RAPIDAPI_HOLIDAYS_VERSION_ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'air-quality',
|
|
||||||
specPath: path.join(__dirname, '..', 'apis', 'air-quality', 'openapi.yaml'),
|
|
||||||
apiId: process.env.RAPIDAPI_AQI_API_ID,
|
|
||||||
versionId: process.env.RAPIDAPI_AQI_VERSION_ID,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a multipart/form-data body from a file buffer.
|
|
||||||
* Returns { body: Buffer, boundary: string }
|
|
||||||
*/
|
|
||||||
function buildMultipart(fieldName, filename, fileBuffer, contentType = 'application/yaml') {
|
|
||||||
const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);
|
|
||||||
const CRLF = '\r\n';
|
|
||||||
const parts = [
|
|
||||||
Buffer.from(
|
|
||||||
`--${boundary}${CRLF}` +
|
|
||||||
`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"${CRLF}` +
|
|
||||||
`Content-Type: ${contentType}${CRLF}${CRLF}`
|
|
||||||
),
|
|
||||||
fileBuffer,
|
|
||||||
Buffer.from(`${CRLF}--${boundary}--${CRLF}`),
|
|
||||||
];
|
|
||||||
return { body: Buffer.concat(parts), boundary };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upload a spec file to RapidAPI Platform API.
|
|
||||||
* Returns a promise that resolves with the response status code.
|
|
||||||
*/
|
|
||||||
function uploadSpec(api) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!api.apiId || !api.versionId) {
|
|
||||||
console.log(`⏭️ Skipping ${api.name}: API ID or Version ID not configured.`);
|
|
||||||
return resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.existsSync(api.specPath)) {
|
|
||||||
console.log(`⏭️ Skipping ${api.name}: spec file not found at ${api.specPath}`);
|
|
||||||
return resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileBuffer = fs.readFileSync(api.specPath);
|
|
||||||
const { body, boundary } = buildMultipart('spec', 'openapi.yaml', fileBuffer);
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
hostname: 'platformapi1.p.rapidapi.com',
|
|
||||||
path: `/v1/apis/${api.apiId}/versions/${api.versionId}`,
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${RAPIDAPI_KEY}`,
|
|
||||||
'X-RapidAPI-Key': RAPIDAPI_KEY,
|
|
||||||
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
'Content-Length': body.length,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const req = https.request(options, (res) => {
|
|
||||||
let data = '';
|
|
||||||
res.on('data', (chunk) => { data += chunk; });
|
|
||||||
res.on('end', () => {
|
|
||||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
console.log(`✓ Published ${api.name} spec to RapidAPI (HTTP ${res.statusCode})`);
|
|
||||||
resolve(res.statusCode);
|
|
||||||
} else {
|
|
||||||
reject(new Error(`Failed to publish ${api.name}: HTTP ${res.statusCode} — ${data}`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('error', reject);
|
|
||||||
req.write(body);
|
|
||||||
req.end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
let hasError = false;
|
|
||||||
for (const api of APIS) {
|
|
||||||
try {
|
|
||||||
await uploadSpec(api);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`✗ ${err.message}`);
|
|
||||||
hasError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasError) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
Reference in New Issue
Block a user