Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Latest commit

 

History

History

README.md

Scripts Directory

This directory contains utility scripts for maintaining the BambooHR API Python SDK.

post_generate.py

Purpose: Runs the full post-generation pipeline after openapi-generator outputs to the project root.

The generator runs with default output (project root), placing package code at bamboohr_sdk/, docs at docs/, etc. This script handles cleanup and processing after generation.

Steps:

  1. Cleans up unwanted generator artifacts (.gitlab-ci.yml, .github/, etc.)
  2. Removes PublicAPIApi files and references (internal-only API)
  3. Formats generated code with ruff
  4. Adds custom headers to API documentation
  5. Cleans up obsolete files (compares old vs new FILES manifest)

Usage: Called automatically by make generate. Not typically run manually.

python scripts/post_generate.py

cleanup_obsolete_files.py

Purpose: Removes files that are no longer generated by the OpenAPI Generator.

How it works:

  1. Before generation, the Makefile backs up .openapi-generator/FILES to .openapi-generator/FILES.old
  2. After generation, this script compares the old and new FILES manifests
  3. Files in the old manifest but not the new one are considered obsolete
  4. The script prompts for confirmation before deleting (unless --force is used)
  5. Empty directories are cleaned up automatically

Usage:

# Automatic (runs as part of make generate with --force)
make generate

# Manual with confirmation prompt
make cleanup-obsolete
# or directly:
python scripts/cleanup_obsolete_files.py

# Force mode (no confirmation, for CI/unattended runs)
python scripts/cleanup_obsolete_files.py --force

First Run: On the first run there will be no .openapi-generator/FILES.old backup, so the script will skip cleanup. This is expected. Subsequent runs will properly detect and remove obsolete files.

generate_exceptions.py

Purpose: Generates the specific exception classes in bamboohr_sdk/exceptions.py from the ERROR_MESSAGES catalog defined in bamboohr_sdk/api_error_helper.py.

Usage: Called automatically by make generate (via post_generate.py). Can also be run manually:

python scripts/generate_exceptions.py

generate_error_docs.py

Purpose: Generates exception documentation in docs/Exceptions/ from the error catalog and mustache templates in templates-python/.

Generates:

  • docs/Exceptions/Exceptions.md — index of all exception classes
  • docs/Exceptions/Classes/<Name>Exception.md — per-exception docs with causes and tips
  • docs/Exceptions/Classes/ApiException.md — base exception documentation
  • docs/Exceptions/Classes/ClientException.md — client exception base documentation
  • docs/Exceptions/Classes/ServerException.md — server exception base documentation

Templates used (from templates-python/):

  • error_codes_doc.mustache — index page template
  • exception_doc.mustache — per-exception page template
  • api_exception_doc.mustache — ApiException page template
  • client_exception_doc.mustache — ClientException page template
  • server_exception_doc.mustache — ServerException page template

Usage: Called automatically by make generate (via post_generate.py). Can also be run manually:

python scripts/generate_error_docs.py

Dependency: Requires chevron (Mustache renderer). Installed automatically with pip install -e ".[dev]".

update_error_docs.py

Purpose: Orchestrates both exception generation scripts in the correct order:

  1. generate_exceptions.py — updates exception classes in bamboohr_sdk/exceptions.py
  2. generate_error_docs.py — generates documentation in docs/Exceptions/

Usage: Called automatically by make generate (via post_generate.py). Can also be run manually:

python scripts/update_error_docs.py
# or
make generate-error-docs

Reference: PHP SDK scripts/update_error_docs.sh


classify_semver.sh

Classifies changes between two OpenAPI specs into a semver bump level (major / minor / patch / none) and optionally applies the version bump to pyproject.toml (Python) or composer.json (PHP). The script is identical across both SDK repos; version-file format is auto-detected.

Part of the automated SDK generation pipeline (epic SPN-2923, tickets SPN-2928 / SPN-2929).

Usage

# Classify only (prints bump level + reasoning)
bash scripts/classify_semver.sh OLD_SPEC NEW_SPEC

# Classify and apply version bump
bash scripts/classify_semver.sh --apply OLD_SPEC NEW_SPEC

# Via Makefile
make classify-semver OLD=specs/public.yaml NEW=/tmp/new-spec.yaml
make classify-semver OLD=specs/public.yaml NEW=/tmp/new-spec.yaml APPLY=true

# Test mode — skip running oasdiff, use pre-generated JSON
bash scripts/classify_semver.sh --changelog-json FILE --breaking-exit N [--apply]

Output

minor
Reason: 2 additive change(s): endpoint-added, new-optional-request-parameter. Highest classification: minor.
Bumped version from 1.0.0 to 1.1.0 in pyproject.toml   # only with --apply

Line 1 is always the bare bump level — easy to capture with $(... | head -1).

Classification Rules

Source Condition Bump
oasdiff breaking --fail-on ERR exit code 1 major
changelog JSON any level: 3 (ERR) entry major (safety net)
changelog JSON any level: 2 (WARN) entry minor
changelog JSON level: 1 entry with an ID in ADDITIVE_IDS minor
changelog JSON level: 1 entry with an unknown ID minor (conservative default)
changelog JSON level: 1 (METADATA_IDS only, no additive/unknown) patch
changelog JSON (after noise filter) empty none

Highest classification wins when multiple change types are present.

Dependencies

  • oasdiffbrew install oasdiff (v1.14.0 tested)
  • jqbrew install jq / apt install jq

oasdiff-severity-levels.txt

Passed to oasdiff via --severity-levels to suppress scope-related check IDs. classify_semver.sh applies this file automatically when it exists alongside the script.

Why This File Exists — The Scope Noise Problem

Running oasdiff changelog against even identical copies of public.yaml produces ~34 api-security-scope-added / api-security-scope-removed entries. These are not real changes. They arise because the public spec has an internal inconsistency: the OAuth scope strings declared in components/securitySchemes differ from those used in individual endpoint security requirements, and oasdiff reports the difference as a scope rename on every comparison.

After confirming that the noise is 100% scope IDs and nothing else, we investigated native oasdiff suppression options:

  • --level WARN — filters all INFO-level output, which removes scope noise but also removes legitimate additive changes like endpoint-added. Too broad.
  • --err-ignore / --warn-ignore — only suppress ERR/WARN level checks; scope changes are INFO level so these flags have no effect.
  • --severity-levels with value none — sets a check's output level to nothing, completely suppressing it. This is the right tool.

Finding: none is an undocumented but valid severity level value (discovered by trial and error). info, warn, error, and none are all accepted; only none fully suppresses a check.

Why scope changes don't matter for SDKs: OAuth scope enforcement is handled at the API gateway layer. Scope changes never affect which SDK methods are generated, their signatures, or their behavior. Excluding them from SDK semver analysis is correct.


tests/

Bash unit tests for classify_semver.sh. Run via make test (runs alongside the primary test suite) or directly:

bash scripts/tests/test_classify_semver.sh

Uses --changelog-json + --breaking-exit to bypass oasdiff, making tests fast and dependency-free (only jq required).

Fixtures (tests/fixtures/)

File Simulates Expected bump
empty.json No spec changes none
additive.json New endpoint (endpoint-added) minor
metadata.json Endpoint deprecated (endpoint-deprecated) patch
breaking.json Endpoint removed (ERR level) major
mixed_additive_and_metadata.json New endpoint + deprecation minor
warn_level.json WARN-level type change minor
noise_only.json Scope changes only none

Research Notes — oasdiff Internals

Level values in changelog JSON

level field oasdiff name Classification
3 ERR major
2 WARN minor
1 INFO minor or patch (depends on ID)

ERR-level changes are also caught by oasdiff breaking --fail-on ERR (exit code 1). The JSON level check is a safety net.

oasdiff changelog does not report text-only changes

oasdiff changelog reports structural changes only. Changes to description, summary, title, example, and other textual fields are NOT included — they appear only in oasdiff diff. A spec update that only changes descriptions produces an empty changelog and is classified as none. No SDK code changes, no version bump.

This means IDs like endpoint-description-changed, api-title-changed, etc. do not exist in oasdiff's check registry. We verified this against the full output of oasdiff checks (293 entries).

Phantom ID Audit

The initial draft of classify_semver.sh contained 21 check IDs that don't exist in oasdiff. Phantom IDs silently fall through to unclassified INFO → minor, so classification remains correct — but reasoning output is poor.

Corrected ADDITIVE_IDS (fake → real):

Phantom Real
response-property-added response-optional-property-added, response-required-property-added
response-status-code-added response-success-status-added
response-mediatype-added response-media-type-added
request-mediatype-added request-body-media-type-added
api-schema-added does not exist
endpoint-tag-added does not exist

Removed METADATA_IDS — all 15 *-description-changed, *-title-changed, *-license-changed, api-schema-deprecated, etc. do not exist in oasdiff checks.

ADDITIVE_IDS Coverage Strategy

Of ~293 total oasdiff checks, ~110 are ERR (caught by oasdiff breaking) and ~23 are WARN (caught by the WARN block). The remaining ~160 are INFO level. ADDITIVE_IDS covers the most commonly occurring ones. Any INFO-level ID not in ADDITIVE_IDS or METADATA_IDS defaults to minor (conservative). This is intentional: unknown additive changes should not be silently downgraded to patch.

METADATA_IDS covers deprecation notices and planned removals — the only INFO-level changes that genuinely warrant just a patch bump.

Run oasdiff checks for the full authoritative list with levels.