mirror of
https://github.com/ashim-hq/ashim
synced 2026-04-21 13:37:52 +00:00
fix: streamline CI/CD — remove broken AI docs updater, fix Docker publish
- Delete ai-docs-updater.yml (never worked: missing ANTHROPIC_API_KEY, tsx not found) - Delete standalone docker-publish.yml (GITHUB_TOKEN can't trigger cross-workflow) - Merge Docker build/push into release.yml as dependent job using .release-version - Add publishCmd to .releaserc.json to signal new releases to Docker job - Fix deploy-docs.yml: upgrade pnpm@v3→v4, node 20→22, add --frozen-lockfile - Fix ci.yml: rename job to "Typecheck" (no lint step existed)
This commit is contained in:
parent
8971debcfc
commit
4f984c83ac
8 changed files with 74 additions and 254 deletions
56
.github/workflows/ai-docs-updater.yml
vendored
56
.github/workflows/ai-docs-updater.yml
vendored
|
|
@ -1,56 +0,0 @@
|
|||
name: AI Documentation Updater
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'apps/api/**'
|
||||
- 'apps/web/**'
|
||||
- 'packages/**'
|
||||
|
||||
jobs:
|
||||
update-docs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2 # Fetch previous commit to get diff
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Generate Diff
|
||||
run: git diff HEAD^ HEAD > diff.patch
|
||||
|
||||
- name: Run Real AI Agent
|
||||
env:
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
run: |
|
||||
echo "Running Claude to analyze changes and update docs..."
|
||||
cd apps/docs && pnpm exec tsx scripts/update-docs.ts ../../diff.patch
|
||||
|
||||
- name: Commit and Push Changes
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add apps/docs/
|
||||
if ! git diff-index --quiet HEAD; then
|
||||
git commit -m "docs: auto-updated by AI 🤖"
|
||||
git push
|
||||
else
|
||||
echo "No documentation changes needed."
|
||||
fi
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -11,8 +11,8 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-and-typecheck:
|
||||
name: Lint & Typecheck
|
||||
typecheck:
|
||||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint-and-typecheck
|
||||
needs: typecheck
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
|
|
|||
8
.github/workflows/deploy-docs.yml
vendored
8
.github/workflows/deploy-docs.yml
vendored
|
|
@ -26,16 +26,14 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 9
|
||||
uses: pnpm/action-setup@v4
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build Docs
|
||||
run: pnpm --filter @stirling-image/docs docs:build
|
||||
- name: Upload artifact
|
||||
|
|
|
|||
65
.github/workflows/docker-publish.yml
vendored
65
.github/workflows/docker-publish.yml
vendored
|
|
@ -1,65 +0,0 @@
|
|||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: docker.io
|
||||
IMAGE_NAME: siddharth123sk/stirling-image
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.IMAGE_NAME }}
|
||||
ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
66
.github/workflows/release.yml
vendored
66
.github/workflows/release.yml
vendored
|
|
@ -8,13 +8,15 @@ permissions:
|
|||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Semantic Release
|
||||
runs-on: ubuntu-latest
|
||||
# Skip release commits to avoid infinite loop
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
outputs:
|
||||
new_version: ${{ steps.check.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -38,3 +40,65 @@ jobs:
|
|||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx semantic-release
|
||||
|
||||
- name: Check for new release
|
||||
id: check
|
||||
run: |
|
||||
if [ -f .release-version ]; then
|
||||
echo "version=$(cat .release-version)" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
docker:
|
||||
name: Build and Push Docker Image
|
||||
needs: release
|
||||
if: needs.release.outputs.new_version != ''
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout release tag
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: v${{ needs.release.outputs.new_version }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
siddharth123sk/stirling-image
|
||||
ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}},value=v${{ needs.release.outputs.new_version }}
|
||||
type=semver,pattern={{major}}.{{minor}},value=v${{ needs.release.outputs.new_version }}
|
||||
type=semver,pattern={{major}},value=v${{ needs.release.outputs.new_version }}
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -35,3 +35,4 @@ settings-*.png
|
|||
layout-*.png
|
||||
audit_report.md
|
||||
.worktrees/
|
||||
.release-version
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
[
|
||||
"@semantic-release/exec",
|
||||
{
|
||||
"prepareCmd": "./scripts/sync-version.sh ${nextRelease.version}"
|
||||
"prepareCmd": "./scripts/sync-version.sh ${nextRelease.version}",
|
||||
"publishCmd": "echo '${nextRelease.version}' > .release-version"
|
||||
}
|
||||
],
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
import { readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// Recursively get all markdown files
|
||||
function getMdFiles(dir: string, fileList: string[] = []): string[] {
|
||||
const files = readdirSync(dir);
|
||||
for (const file of files) {
|
||||
const filePath = path.join(dir, file);
|
||||
if (statSync(filePath).isDirectory()) {
|
||||
if (file !== 'node_modules' && file !== '.vitepress' && file !== 'scripts') {
|
||||
getMdFiles(filePath, fileList);
|
||||
}
|
||||
} else if (file.endsWith('.md')) {
|
||||
fileList.push(filePath);
|
||||
}
|
||||
}
|
||||
return fileList;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY;
|
||||
if (!apiKey) {
|
||||
console.error("ANTHROPIC_API_KEY environment variable is missing.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const diffPath = process.argv[2];
|
||||
if (!diffPath) {
|
||||
console.error("Please provide the path to the diff file. Usage: npx tsx apps/docs/scripts/update-docs.ts <path-to-diff>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const diffContent = readFileSync(path.resolve(process.cwd(), diffPath), 'utf-8');
|
||||
if (!diffContent.trim()) {
|
||||
console.log("No diff content. Exiting.");
|
||||
return;
|
||||
}
|
||||
|
||||
const docsDir = path.resolve(__dirname, '..');
|
||||
const mdFiles = getMdFiles(docsDir);
|
||||
|
||||
const docsContext = mdFiles.map(file => {
|
||||
const relativePath = path.relative(docsDir, file);
|
||||
const content = readFileSync(file, 'utf-8');
|
||||
return `--- FILE: ${relativePath} ---\n${content}\n`;
|
||||
}).join('\n');
|
||||
|
||||
const prompt = `You are an expert technical writer and developer maintaining documentation for a project.
|
||||
A code change has just been merged.
|
||||
|
||||
Here is the git diff of the code changes:
|
||||
\`\`\`diff
|
||||
${diffContent}
|
||||
\`\`\`
|
||||
|
||||
Here is the current VitePress documentation (Markdown files):
|
||||
${docsContext}
|
||||
|
||||
Task:
|
||||
Analyze the git diff and determine if any of the documentation files need to be updated to reflect these code changes.
|
||||
If updates are needed, output a JSON array of objects with 'file' and 'content' properties.
|
||||
- 'file' MUST be the exact relative path of the file to update (e.g., 'guide/architecture.md').
|
||||
- 'content' MUST be the complete, updated markdown content for that file.
|
||||
If no updates are needed, output an empty array: []
|
||||
|
||||
IMPORTANT: Respond ONLY with valid JSON. Do not include markdown formatting like \`\`\`json around your response. Just the raw JSON array.`;
|
||||
|
||||
console.log("Sending diff and current docs to Claude API...");
|
||||
|
||||
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': apiKey,
|
||||
'anthropic-version': '2023-06-01'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: "claude-3-5-sonnet-20241022",
|
||||
max_tokens: 4096,
|
||||
messages: [{ role: "user", content: prompt }]
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error(\`API Error (\${response.status}):\`, errorText);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const responseText = data.content?.[0]?.text;
|
||||
|
||||
if (!responseText) {
|
||||
console.log("No response text from AI.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const updates = JSON.parse(responseText);
|
||||
if (!Array.isArray(updates) || updates.length === 0) {
|
||||
console.log("AI determined no documentation updates are needed.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const update of updates) {
|
||||
if (update.file && update.content) {
|
||||
const fullPath = path.join(docsDir, update.file);
|
||||
writeFileSync(fullPath, update.content, 'utf-8');
|
||||
console.log(\`Successfully updated \${update.file}\`);
|
||||
}
|
||||
}
|
||||
console.log("Documentation update complete.");
|
||||
} catch (e) {
|
||||
console.error("Failed to parse AI response as JSON", e);
|
||||
console.log("Raw Response:", responseText);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error("An unexpected error occurred:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in a new issue