name: Stainless SDK Builds run-name: Build Stainless SDK from OpenAPI spec changes # This workflow uses pull_request_target, which allows it to run on pull requests # from forks with access to secrets. This is safe because the workflow definition # comes from the base branch (trusted), and the action only reads OpenAPI spec # files without executing any code from the PR. on: pull_request_target: types: - opened - synchronize - reopened - closed paths: - "client-sdks/stainless/**" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} cancel-in-progress: true env: # Stainless organization name. STAINLESS_ORG: llamastack # Stainless project name. STAINLESS_PROJECT: llama-stack-client # Path to your OpenAPI spec. OAS_PATH: ./client-sdks/stainless/openapi.yml # Path to your Stainless config. Optional; only provide this if you prefer # to maintain the ground truth Stainless config in your own repo. CONFIG_PATH: ./client-sdks/stainless/config.yml # When to fail the job based on build conclusion. # Options: "never" | "note" | "warning" | "error" | "fatal". FAIL_ON: error # In your repo secrets, configure: # - STAINLESS_API_KEY: a Stainless API key, which you can generate on the # Stainless organization dashboard jobs: preview: if: github.event.action != 'closed' runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: # Checkout the PR's code to access the OpenAPI spec and config files. # This is necessary to read the spec/config from the PR (including from forks). - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 # Compute the Stainless branch name, prefixing with fork owner if PR is from a fork. # For fork PRs like "contributor:fix/issue-123", this creates "preview/contributor/fix/issue-123" # For same-repo PRs, this creates "preview/fix/issue-123" - name: Compute branch names id: branch-names run: | HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}" BASE_REPO="${{ github.repository }}" BRANCH_NAME="${{ github.event.pull_request.head.ref }}" if [ "$HEAD_REPO" != "$BASE_REPO" ]; then # Fork PR: prefix with fork owner for isolation FORK_OWNER="${{ github.event.pull_request.head.repo.owner.login }}" PREVIEW_BRANCH="preview/${FORK_OWNER}/${BRANCH_NAME}" BASE_BRANCH="preview/base/${FORK_OWNER}/${BRANCH_NAME}" else # Same-repo PR PREVIEW_BRANCH="preview/${BRANCH_NAME}" BASE_BRANCH="preview/base/${BRANCH_NAME}" fi echo "preview_branch=${PREVIEW_BRANCH}" >> $GITHUB_OUTPUT echo "base_branch=${BASE_BRANCH}" >> $GITHUB_OUTPUT # This action builds preview SDKs from the OpenAPI spec changes and # posts/updates a comment on the PR with build results and links to the preview. - name: Run preview builds uses: stainless-api/upload-openapi-spec-action/preview@32823b096b4319c53ee948d702d9052873af485f # 1.6.0 with: stainless_api_key: ${{ secrets.STAINLESS_API_KEY }} org: ${{ env.STAINLESS_ORG }} project: ${{ env.STAINLESS_PROJECT }} oas_path: ${{ env.OAS_PATH }} config_path: ${{ env.CONFIG_PATH }} fail_on: ${{ env.FAIL_ON }} base_sha: ${{ github.event.pull_request.base.sha }} base_ref: ${{ github.event.pull_request.base.ref }} head_sha: ${{ github.event.pull_request.head.sha }} branch: ${{ steps.branch-names.outputs.preview_branch }} base_branch: ${{ steps.branch-names.outputs.base_branch }} merge: if: github.event.action == 'closed' && github.event.pull_request.merged == true runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: # Checkout the PR's code to access the OpenAPI spec and config files. # This is necessary to read the spec/config from the PR (including from forks). - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 # Compute the Stainless branch name, prefixing with fork owner if PR is from a fork. # For fork PRs like "contributor:fix/issue-123", this creates "preview/contributor/fix/issue-123" # For same-repo PRs, this creates "preview/fix/issue-123" - name: Compute branch names id: branch-names run: | HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}" BASE_REPO="${{ github.repository }}" BRANCH_NAME="${{ github.event.pull_request.head.ref }}" if [ "$HEAD_REPO" != "$BASE_REPO" ]; then # Fork PR: prefix with fork owner for isolation FORK_OWNER="${{ github.event.pull_request.head.repo.owner.login }}" MERGE_BRANCH="preview/${FORK_OWNER}/${BRANCH_NAME}" else # Same-repo PR MERGE_BRANCH="preview/${BRANCH_NAME}" fi echo "merge_branch=${MERGE_BRANCH}" >> $GITHUB_OUTPUT # Note that this only merges in changes that happened on the last build on # the computed preview branch. It's possible that there are OAS/config # changes that haven't been built, if the preview job didn't finish # before this step starts. In theory we want to wait for all builds # against the preview branch to complete, but assuming that # the preview job happens before the PR merge, it should be fine. - name: Run merge build uses: stainless-api/upload-openapi-spec-action/merge@32823b096b4319c53ee948d702d9052873af485f # 1.6.0 with: stainless_api_key: ${{ secrets.STAINLESS_API_KEY }} org: ${{ env.STAINLESS_ORG }} project: ${{ env.STAINLESS_PROJECT }} oas_path: ${{ env.OAS_PATH }} config_path: ${{ env.CONFIG_PATH }} fail_on: ${{ env.FAIL_ON }} base_sha: ${{ github.event.pull_request.base.sha }} base_ref: ${{ github.event.pull_request.base.ref }} head_sha: ${{ github.event.pull_request.head.sha }} merge_branch: ${{ steps.branch-names.outputs.merge_branch }}