unleash

GitHub

Open-source feature management platform

Raw JSON API

unleash Specification

Located in .github/workflows/openapi-diff.yaml on branch HEAD

Unknown YAML 9.0 KB
Raw YAML Specification
name: OpenAPI Diff

concurrency:
  group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
  cancel-in-progress: true

on:
  pull_request:
    paths:
      - src/lib/**
      - scripts/check-edge-openapi-routes.sh
      - .github/workflows/openapi-diff.yaml
  workflow_dispatch:
    inputs:
      baseline_version:
        description: 'Stable Unleash version or commit SHA to compare against (e.g. v6.9.3, or a commit SHA).'
        required: true

jobs:
  generate-openapi-stable:
    name: Generate OpenAPI (stable)
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_INITDB_ARGS: "--no-sync"
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Determine baseline commit
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            git fetch origin "${{ github.event.pull_request.base.ref }}"
            BASE_SHA=$(git merge-base "origin/${{ github.event.pull_request.base.ref }}" "${{ github.sha }}")
          else
            # workflow_dispatch: baseline_version is required
            git fetch --tags origin
            BASE_SHA=$(git rev-parse "${{ github.event.inputs.baseline_version }}")
          fi
          echo "BASE_SHA=$BASE_SHA" >> $GITHUB_ENV
      - name: Checkout baseline commit
        run: git checkout "${BASE_SHA}"
      - uses: pnpm/action-setup@v5
      - name: Install node
        uses: actions/setup-node@v6
        with:
          node-version: 22.x
      - name: Install dependencies
        run: |
          pnpm install --frozen-lockfile
      - name: Start Unleash test instance
        run: |
          # fake frontend build
          mkdir -p frontend/build
          touch frontend/build/index.html
          touch frontend/build/favicon.ico
          # end fake frontend build

          # start unleash in background
          NODE_ENV=openapi pnpm dev:backend > /tmp/unleash-server.log 2>&1 &
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
          DATABASE_SSL: 'false'
          CHECK_VERSION: 'false'
      - name: Wait for Unleash to be ready
        run: |
          for i in {1..30}; do
            if curl -sf http://localhost:4242/health; then
              echo "Unleash is up!";
              exit 0
            fi
            echo "Waiting for Unleash... attempt $i";
            sleep 2
          done
          echo "Unleash did not become ready in time."
          cat /tmp/unleash-server.log
          exit 1
      - name: Download OpenAPI spec from baseline
        run: curl -sSL -o openapi-stable.json "http://localhost:4242/docs/openapi.json"
      - name: Upload openapi-stable.json
        uses: actions/upload-artifact@v7
        with:
          name: openapi-stable
          path: openapi-stable.json

  generate-openapi-current:
    name: Generate OpenAPI (current branch)
    runs-on: ubuntu-latest
    services:
      # Label used to access the service container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_INITDB_ARGS: "--no-sync"
        # Set health checks to wait until postgres has started
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
    steps:
      - uses: actions/checkout@v6
      - uses: pnpm/action-setup@v5
      - name: Install node
        uses: actions/setup-node@v6
        with:
          node-version: 22.x
      - name: Install dependencies
        run: |
          pnpm install --frozen-lockfile
      - name: Start Unleash test instance
        run: |
          # fake frontend build
          mkdir -p frontend/build
          touch frontend/build/index.html
          touch frontend/build/favicon.ico
          # end fake frontend build

          # start unleash in background
          NODE_ENV=openapi pnpm dev:backend > /tmp/unleash-server.log 2>&1 &
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
          DATABASE_SSL: 'false'
          CHECK_VERSION: 'false'
      - name: Wait for Unleash to be ready
        run: |
          for i in {1..30}; do
            if curl -sf http://localhost:4242/health; then
              echo "Unleash is up!";
              exit 0
            fi
            echo "Waiting for Unleash... attempt $i";
            sleep 2
          done
          echo "Unleash did not become ready in time."
          cat /tmp/unleash-server.log
          exit 1
      - name: Download OpenAPI spec (current branch)
        run: curl -sSL -o openapi-current.json http://localhost:4242/docs/openapi.json
      - name: Upload openapi-current.json
        uses: actions/upload-artifact@v7
        with:
          name: openapi-current
          path: openapi-current.json

  openapi-diff:
    name: OpenAPI Diff
    runs-on: ubuntu-latest
    needs: [generate-openapi-current, generate-openapi-stable]
    if: github.event_name == 'pull_request'
    steps:
      - name: Download openapi-current.json
        uses: actions/download-artifact@v8
        with:
          name: openapi-current
      - name: Download openapi-stable.json
        uses: actions/download-artifact@v8
        with:
          name: openapi-stable
      - name: Run OpenAPI diff
        id: diff
        run: |
          docker run --rm -t -v $(pwd):/specs:ro tufin/oasdiff changelog --format markdown /specs/openapi-stable.json /specs/openapi-current.json > openapi-diff.txt || true
          # then output in a format that is useful when you go inside the job output
          docker run --rm -t -v $(pwd):/specs:ro tufin/oasdiff changelog --format githubactions /specs/openapi-stable.json /specs/openapi-current.json
      - name: Show OpenAPI diff
        if: github.event_name != 'pull_request'
        run: cat openapi-diff.txt
      - name: Comment on PR with OpenAPI diff
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v9
        with:
          script: |
            const fs = require('fs');
            const diff = fs.readFileSync('openapi-diff.txt', 'utf8');
            const diffLines = diff.split('\n').filter(line => line.trim() !== '' && !line.startsWith('#')).length;
            const marker = '[//]: # (OpenAPI diff - used to identify the comment)';
            // Get all comments on the PR
            const { data: comments } = await github.rest.issues.listComments({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
            });
            // Find existing OpenAPI Diff comment
            const existing = comments.find(c => c.body && c.body.includes(marker) && c.user.type === 'Bot');
            let body;
            if (diffLines > 300) {
              body = `${marker} too long, check the this task output for details.`;
              console.log(diff);
            } else if (diffLines > 0) {
              body = `${marker}\n${diff}`;
            } else {
              body = null;
            }
            if (body) {
              if (existing) {
                await github.rest.issues.updateComment({
                  comment_id: existing.id,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  body,
                });
              } else {
                await github.rest.issues.createComment({
                  issue_number: context.issue.number,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  body,
                });
              }
            } else {
              console.log('No significant changes detected in OpenAPI spec.');
              if (existing) {
                await github.rest.issues.deleteComment({
                  comment_id: existing.id,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                });
              }
            }

  edge-openapi-routes:
    name: Check Edge OpenAPI routes
    runs-on: ubuntu-latest
    needs: [generate-openapi-current]
    steps:
      - uses: actions/checkout@v6

      - name: Download openapi-current.json
        uses: actions/download-artifact@v8
        with:
          name: openapi-current

      - name: Download Edge OpenAPI spec
        run: |
          curl -fsSL -o edge-openapi.json https://hosted.edge.getunleash.io/docs/openapi.json

          jq empty openapi-current.json
          jq empty edge-openapi.json

      - name: Write allowed route exceptions
        run: |
          cat > edge-route-exceptions.txt <<'EOF'
          POST /api/client/metrics/custom
          EOF

      - name: Check Edge contains all required client routes
        run: scripts/check-edge-openapi-routes.sh openapi-current.json edge-openapi.json edge-route-exceptions.txt