Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/.github/** export-ignore
/docs/** export-ignore
/generator/** export-ignore
/fern/fern.config.json export-ignore
/fern/generators.yaml export-ignore
/fern/sdk/.fern/** export-ignore
/fern/sdk/.github/** export-ignore
/fern/sdk/composer.lock export-ignore
/fern/sdk/phpstan.neon export-ignore
/fern/sdk/phpunit.xml export-ignore
/fern/sdk/tests/** export-ignore
/fern/sdk/vendor/** export-ignore
/fern/sdk/wiremock/** export-ignore
34 changes: 34 additions & 0 deletions .github/workflows/docs-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Validate documentation

on:
pull_request:
paths:
- 'docs/**'
- 'generator/scripts/prepare_docs.py'
- 'generator/tests/*docs*'
- '.github/workflows/*docs*'
workflow_dispatch:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: docs
- name: Check conversion and reproducibility
run: |
python3 -m unittest discover -s generator/tests -p 'test_*docs*.py'
python3 generator/scripts/prepare_docs.py
git diff --exit-code -- docs
- name: Build with GitHub Pages dependencies
working-directory: docs
run: bundle exec jekyll build --destination ../_site
- name: Check rendered links and method disclosures
run: python3 generator/tests/check_docs_site.py _site
53 changes: 0 additions & 53 deletions .github/workflows/main.yml

This file was deleted.

89 changes: 89 additions & 0 deletions .github/workflows/php-sdk-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Validate PHP SDK

on:
push:
branches: [main]
pull_request:
paths:
- ".gitattributes"
- "composer.json"
- "fern/**"
- "generator/**"
- "README.md"
- "docs/**"
- ".github/workflows/**"
Comment thread
paketeserrano marked this conversation as resolved.
Resolved
workflow_dispatch:
inputs:
ref:
description: "Branch or commit to validate"
required: true
type: string
pr_number:
description: "Generated pull request number"
required: false
type: string

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ["8.1", "8.2"]
env:
TARGET_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || inputs.ref || github.sha }}
TARGET_REPOSITORY: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
steps:
- name: Check out target
uses: actions/checkout@v4
with:
repository: ${{ env.TARGET_REPOSITORY }}
ref: ${{ env.TARGET_REF }}

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
tools: composer

- uses: actions/setup-node@v4
with:
node-version: "24"

- name: Test release trust and registry verification offline
run: node --test generator/tests/release.test.mjs

- name: Validate the Packagist package and autoload
run: |
composer validate --no-check-publish
composer install --no-dev --no-interaction --prefer-dist --no-progress
php -r 'require "vendor/autoload.php"; if (!class_exists("Upcloud\\UpcloudClient")) { exit(1); }'

- name: Install dependencies
run: composer install --no-interaction --prefer-dist --working-dir fern/sdk

- name: Test OpenAPI preprocessing
run: python3 -m unittest discover -s generator/tests -p 'test_*.py'

- name: Build PHP SDK
run: composer build --working-dir fern/sdk

- name: Smoke test generated SDK
run: php generator/tests/generated_sdk_smoke.php

- name: Check endpoint coverage
run: python3 generator/tests/check_endpoint_coverage.py generator/openapi/spec.json fern/sdk/src

- name: Test generated request behavior
run: php generator/tests/generated_request_behavior.php

- name: Test generated model fixtures
run: php generator/tests/generated_model_fixtures.php

- name: Run PHPUnit and generated WireMock tests
run: composer test --working-dir fern/sdk

- name: Run PHPStan
run: composer analyze --working-dir fern/sdk
124 changes: 124 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Publish PHP SDK

on:
workflow_run:
workflows: ["Build PHP SDK Release"]
types: [completed]

permissions:
contents: read
actions: read

jobs:
publish:
if: >-
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
concurrency:
group: sdk-packagist-publication
cancel-in-progress: false

steps:
- name: Require explicit Packagist publishing enablement
env:
PACKAGIST_PUBLISH_ENABLED: ${{ vars.PACKAGIST_PUBLISH_ENABLED }}
run: |
if [[ "$PACKAGIST_PUBLISH_ENABLED" != true ]]; then
echo "::error::Configure the existing Packagist package to use this repository, then set PACKAGIST_PUBLISH_ENABLED=true."
exit 1
fi

- uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
tools: composer

- name: Download identity from the successful release run
uses: actions/download-artifact@v4
with:
name: sdk-release-identity
path: release-identity
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}

- name: Validate explicit release identity
id: get_tag
env:
RELEASE_COMMIT: ${{ github.event.workflow_run.head_sha }}
RELEASE_RUN_ID: ${{ github.event.workflow_run.id }}
run: |
set -euo pipefail
RELEASE_TAG="$(php -r '
$identity = json_decode(file_get_contents("release-identity/release.json"), true, 512, JSON_THROW_ON_ERROR);
if (($identity["commit"] ?? null) !== getenv("RELEASE_COMMIT")
|| ($identity["repository"] ?? null) !== getenv("GITHUB_REPOSITORY")
|| ($identity["run_id"] ?? null) !== getenv("RELEASE_RUN_ID")
|| !is_string($identity["tag"] ?? null)) {
fwrite(STDERR, "Release identity does not match the successful workflow run\n");
exit(1);
}
echo $identity["tag"];
')"
if [[ ! "$RELEASE_TAG" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-(alpha|beta|rc)(\.(0|[1-9][0-9]*))?)?$ ]]; then
echo "::error::Expected vX.Y.Z or an alpha, beta, or rc tag, received '$RELEASE_TAG'."
exit 1
fi
echo "tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
echo "Publishing PHP SDK for tag: $RELEASE_TAG"

- name: Check out the exact release commit
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
persist-credentials: false

- name: Verify release tag and commit are on the default branch
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
RELEASE_TAG: ${{ steps.get_tag.outputs.tag }}
RELEASE_COMMIT: ${{ github.event.workflow_run.head_sha }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
AUTH_HEADER="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')"
git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${AUTH_HEADER}" \
fetch --no-tags origin "+refs/heads/${DEFAULT_BRANCH}:refs/release-verification/main" \
"+refs/tags/${RELEASE_TAG}:refs/release-verification/tag"
unset AUTH_HEADER
TAG_COMMIT="$(git rev-parse "refs/release-verification/tag^{commit}")"
if [[ "$TAG_COMMIT" != "$RELEASE_COMMIT" || "$(git rev-parse HEAD)" != "$RELEASE_COMMIT" ]]; then
echo "::error::Tag $RELEASE_TAG no longer points to the release workflow commit."
exit 1
fi
if ! git merge-base --is-ancestor "$RELEASE_COMMIT" refs/release-verification/main; then
echo "::error::Release commit is not on the history of $DEFAULT_BRANCH."
exit 1
fi
echo "Verified $RELEASE_TAG ($RELEASE_COMMIT) is on $DEFAULT_BRANCH."

- name: Publish to Packagist
env:
PACKAGIST_USERNAME: ${{ secrets.PACKAGIST_USERNAME }}
PACKAGIST_TOKEN: ${{ secrets.PACKAGIST_TOKEN }}
RELEASE_COMMIT: ${{ github.event.workflow_run.head_sha }}
RELEASE_TAG: ${{ steps.get_tag.outputs.tag }}
run: |
set -euo pipefail
chmod +x generator/scripts/publish.sh
bash generator/scripts/publish.sh "$RELEASE_TAG"

- name: Record Packagist publication proof
run: |
echo "## Packagist publication verified" >> "$GITHUB_STEP_SUMMARY"
echo '```json' >> "$GITHUB_STEP_SUMMARY"
cat publication-receipt.json >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"

- uses: actions/upload-artifact@v4
with:
name: packagist-publication-proof
path: publication-receipt.json
if-no-files-found: error
Loading
Loading