diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58ea7a4..a88f63b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,30 @@ on: branches: [ "main" ] jobs: + changes: + name: Detect Changed Paths + runs-on: ubuntu-latest + outputs: + typescript: ${{ steps.filter.outputs.typescript }} + python: ${{ steps.filter.outputs.python }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + typescript: + - 'packages/smooth-api-ts/**' + - 'sandbox/**' + - '.github/workflows/ci.yml' + python: + - 'packages/smooth-api-py/**' + - 'sandbox/**' + - '.github/workflows/ci.yml' + typescript-tests: + needs: changes + if: ${{ needs.changes.outputs.typescript == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -43,6 +66,8 @@ jobs: npm test python-tests: + needs: changes + if: ${{ needs.changes.outputs.python == 'true' }} runs-on: ubuntu-latest strategy: matrix: @@ -83,3 +108,4 @@ jobs: - name: Run Python tests working-directory: ./packages/smooth-api-py run: pytest tests/ -v + diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml new file mode 100644 index 0000000..e75574d --- /dev/null +++ b/.github/workflows/deploy-website.yml @@ -0,0 +1,68 @@ +name: Deploy Website + +on: + workflow_dispatch: + inputs: + environment: + description: 'Target Environment' + required: true + default: 'production' + type: choice + options: + - production + - preview + +jobs: + deploy: + name: Deploy to Vercel + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install Vercel CLI + run: npm install --global vercel@latest + + - name: Pull Vercel Environment Information + working-directory: ./website + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + run: | + if [ "${{ inputs.environment }}" = "production" ]; then + vercel pull --yes --environment=production --token=$VERCEL_TOKEN + else + vercel pull --yes --environment=preview --token=$VERCEL_TOKEN + fi + + - name: Build Project Artifacts + working-directory: ./website + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + run: | + if [ "${{ inputs.environment }}" = "production" ]; then + vercel build --prod --token=$VERCEL_TOKEN + else + vercel build --token=$VERCEL_TOKEN + fi + + - name: Deploy Project Artifacts to Vercel + working-directory: ./website + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + run: | + if [ "${{ inputs.environment }}" = "production" ]; then + vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN + else + vercel deploy --prebuilt --token=$VERCEL_TOKEN + fi diff --git a/.github/workflows/website-ci.yml b/.github/workflows/website-ci.yml new file mode 100644 index 0000000..7773597 --- /dev/null +++ b/.github/workflows/website-ci.yml @@ -0,0 +1,38 @@ +name: Website CI + +on: + push: + branches: [ "main" ] + paths: + - 'website/**' + - '.github/workflows/website-ci.yml' + pull_request: + branches: [ "main" ] + paths: + - 'website/**' + - '.github/workflows/website-ci.yml' + +jobs: + website-build: + name: Website Build & Format Check + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install website dependencies + working-directory: ./website + run: npm ci + + - name: Check website formatting + working-directory: ./website + run: npm run format:check + + - name: Build website + working-directory: ./website + run: npm run build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a708080..40f991f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,6 +118,45 @@ The server runs on `http://localhost:3001` and provides `/health`, `/chaos`, and --- +### Documentation Website (`website`) + +1. **Install dependencies**: + ```bash + cd website + npm install + ``` + +2. **Format and build**: + Verify formatting and ensure the production build succeeds: + ```bash + npm run format:check + npm run build + ``` + To automatically fix formatting issues: + ```bash + npm run format + ``` + +--- + +## Continuous Integration (CI) Expectations + +SmoothAPI uses path-aware CI workflows to keep feedback fast and low-friction for contributors: + +- **TypeScript changes**: Runs build, typecheck, and test suite. +- **Python changes**: Runs pytest suite across supported Python versions. +- **Website changes**: Runs website dependency install, formatting check (`npm run format:check`), and Next.js build (`npm run build`). + +> [!NOTE] +> CI workflows automatically skip jobs for packages or components that were not modified in your Pull Request. + +### Contributor Access & Deployments +- External contributors **do NOT need** Vercel access, Vercel team membership, or deployment credentials. +- Automatic Git-triggered Vercel preview deployments are disabled on Pull Requests. +- Maintainers handle production deployments manually via maintainer-triggered GitHub Actions after code review. + +--- + ## Coding Standards & Quality To keep the repository clean, please adhere to these guidelines: @@ -152,3 +191,4 @@ We encourage semantic/structured commit messages to help automate release notes 4. Run the full test suite with the local sandbox running. 5. Update documentation if you are changing or introducing features. 6. Open a Pull Request pointing to the `main` branch. Provide a clear description of the problem solved, changes made, and proof of testing. + diff --git a/website/AGENTS.md b/website/AGENTS.md index 8bd0e39..caeace2 100644 --- a/website/AGENTS.md +++ b/website/AGENTS.md @@ -1,4 +1,5 @@ + # This is NOT the Next.js you know This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. diff --git a/website/package.json b/website/package.json index f7e5e47..ef7b089 100644 --- a/website/package.json +++ b/website/package.json @@ -6,7 +6,9 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "next": "16.2.9", @@ -20,6 +22,7 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.2.9", + "prettier": "^3.5.0", "tailwindcss": "^4", "typescript": "^5" } diff --git a/website/src/app/globals.css b/website/src/app/globals.css index f1836c6..bf4328f 100644 --- a/website/src/app/globals.css +++ b/website/src/app/globals.css @@ -16,7 +16,8 @@ --warning: #f59e0b; } -html, body { +html, +body { background-color: var(--background); color: var(--foreground); scroll-behavior: smooth; diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx index cef35ac..48f8e79 100644 --- a/website/src/app/layout.tsx +++ b/website/src/app/layout.tsx @@ -9,10 +9,11 @@ const sansFont = Plus_Jakarta_Sans({ export const metadata: Metadata = { title: "SmoothAPI", - description: "Zero-dependency, dual-language API self-healing and fault-tolerance library. Implemented natively in TypeScript and Python with exponential backoff and circuit breaking.", + description: + "Zero-dependency, dual-language API self-healing and fault-tolerance library. Implemented natively in TypeScript and Python with exponential backoff and circuit breaking.", icons: { icon: "/icon.svg", - } + }, }; export default function RootLayout({ @@ -21,10 +22,7 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - +
{children} diff --git a/website/src/app/page.tsx b/website/src/app/page.tsx index 26c9c37..585287a 100644 --- a/website/src/app/page.tsx +++ b/website/src/app/page.tsx @@ -174,25 +174,57 @@ export default function Home() { return (