From ea6906263408d9009a0a73d4aa228ecca0d88c3b Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Mon, 26 Jan 2026 14:16:41 -0700 Subject: [PATCH 01/11] Update config files for multi version handling --- openapi/config-latest.yml | 7 ------- openapi/config-v20111101.yml | 3 ++- openapi/config-v20250224.yml | 3 ++- openapi/{config.yml => config.yml.bak} | 1 + 4 files changed, 5 insertions(+), 9 deletions(-) delete mode 100644 openapi/config-latest.yml rename openapi/{config.yml => config.yml.bak} (75%) diff --git a/openapi/config-latest.yml b/openapi/config-latest.yml deleted file mode 100644 index d2b2b24..0000000 --- a/openapi/config-latest.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Latest is mapped to v20111101 for now to maintain backwards compatibility. -# In the future, this will point to the latest version of the API. ---- -generatorName: typescript-axios -npmName: mx-platform-node -npmVersion: 2.0.0 -supportsES6: true diff --git a/openapi/config-v20111101.yml b/openapi/config-v20111101.yml index 5e3a8dc..f4caae4 100644 --- a/openapi/config-v20111101.yml +++ b/openapi/config-v20111101.yml @@ -1,5 +1,6 @@ --- generatorName: typescript-axios -npmName: mx-platform-node-v20111101 +npmName: mx-platform-node npmVersion: 2.0.0 supportsES6: true +.openapi-generator-ignore: true diff --git a/openapi/config-v20250224.yml b/openapi/config-v20250224.yml index 5a3e7e1..8184260 100644 --- a/openapi/config-v20250224.yml +++ b/openapi/config-v20250224.yml @@ -1,5 +1,6 @@ --- generatorName: typescript-axios -npmName: mx-platform-node-v20250224 +npmName: mx-platform-node npmVersion: 3.0.0 supportsES6: true +.openapi-generator-ignore: true diff --git a/openapi/config.yml b/openapi/config.yml.bak similarity index 75% rename from openapi/config.yml rename to openapi/config.yml.bak index 5efac3a..cb020e7 100644 --- a/openapi/config.yml +++ b/openapi/config.yml.bak @@ -1,3 +1,4 @@ +# Archived to support multiple versions. Reference --- npmName: mx-platform-node npmVersion: 2.0.0-rc.1 # Pre-release for testing new directory structure From badcf81842d46315826a8d208b2935dfbf6f068f Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Mon, 26 Jan 2026 14:17:00 -0700 Subject: [PATCH 02/11] Create Flow document for reference --- docs/SDK-Generation-Publishing-Flow.md | 410 +++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 docs/SDK-Generation-Publishing-Flow.md diff --git a/docs/SDK-Generation-Publishing-Flow.md b/docs/SDK-Generation-Publishing-Flow.md new file mode 100644 index 0000000..03a47ae --- /dev/null +++ b/docs/SDK-Generation-Publishing-Flow.md @@ -0,0 +1,410 @@ +# SDK Generation, Publishing, and Release Flow + +**Document Purpose**: This document explains how the Node.js SDK is automatically generated, published to npm, and released. It covers both automatic triggers (from the OpenAPI repository) and manual generation flows (for development and testing). This is a reference guide for developers new to this repository. + +**Last Updated**: January 20, 2026 +**Repository**: mx-platform-node +**Author**: DevExperience Team + +--- + +## Overview + +The mx-platform-node repository has a fully automated pipeline for generating TypeScript SDKs from OpenAPI specifications, publishing them to npm, and creating releases on GitHub. The process is triggered in two ways: + +1. **Automatic Flow** - When OpenAPI specifications change in the upstream `openapi` repository +2. **Manual Flow** - When developers manually trigger generation for development, testing, or version bumps + +Both flows use the same underlying generation logic but differ in how they handle commits, publishing, and release creation. + +--- + +## Flow 1: Automatic Generation (Repository Dispatch) + +### Trigger +OpenAPI specifications in the upstream `openapi` repository change → Repository sends `repository_dispatch` event to `mx-platform-node` → `generate_publish_release.yml` workflow is triggered + +### Current Implementation + +**Workflow**: `.github/workflows/generate_publish_release.yml` + +This is the **production flow** that automatically generates, publishes, and releases SDKs when upstream APIs change. + +#### Step 1: Generate SDK from OpenAPI Spec +- **Input**: OpenAPI specification from `https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/mx_platform_api.yml` +- **Output Directory**: `./latest/` +- **Configuration**: Uses `./openapi/config.yml` to control generation settings + - Package name: `mx-platform-node` + - **Package version source**: `npmVersion` field in `./openapi/config.yml` (the source of truth) + - **Version bump**: `client_payload.version` from repository dispatch (e.g., "patch", "minor") tells `version.rb` which component to increment + - Flow: `client_payload.version` (bump instruction) → `version.rb` reads config → updates `npmVersion` in config → `package.mustache` uses updated `npmVersion` to create `package.json` +- **Templates**: Uses `./openapi/templates/` (package.mustache, README.mustache, etc.) +- **Process**: + 1. Clean repository using `clean.rb` (removes old generated files) + 2. Bump version: `version.rb` reads current `npmVersion` from config, increments based on `client_payload.version`, writes updated version back to config + 3. Run OpenAPI Generator to create TypeScript-Axios SDK (uses updated config with new `npmVersion`) + 4. Copy documentation files (LICENSE, CHANGELOG.md, MIGRATION.md) to generated directory + +#### Step 2: Commit Changes to Master +- **Git Config**: Uses `devexperience` bot account +- **Commit Message**: `"Generated version X.Y.Z - This commit was automatically created by a GitHub Action..."` +- **Target Branch**: Directly commits to `master` (no PR created) + +#### Step 3: Publish to npm +- **Trigger**: After successful commit, dispatches `publish_sdk` repository_dispatch event +- **Workflow**: `.github/workflows/publish.yml` (triggered via repository_dispatch) +- **Process**: + 1. Navigate to `./latest/` directory + 2. Install dependencies: `npm install` + 3. Publish to npm registry with `--tag next` + 4. Uses NPM_AUTH_TOKEN secret for authentication + +#### Step 4: Create GitHub Release +- **Trigger**: After successful publish, dispatches `release_sdk` repository_dispatch event +- **Workflow**: `.github/workflows/release.yml` (triggered via repository_dispatch) +- **Process**: + 1. Read version from `./latest/package.json` + 2. Create GitHub release tagged with version (e.g., `v2.0.5`) + 3. Slack notification on failure + +--- + +## Flow 2: Manual Generation (Workflow Dispatch) + +### Trigger +Developer manually clicks "Run workflow" on `generate.yml` in GitHub Actions UI + +### User Inputs +The workflow accepts two parameters: +- **version_level**: Which version component to bump (major, minor, or patch) +- Default: patch + +### Current Implementation + +**Workflow**: `.github/workflows/generate.yml` + +This flow is used for: +- Development and testing +- Creating PRs with proposed SDK updates +- Manual version bumping before merging + +#### Step 1: Version Bumping +- **Script**: `ruby .github/version.rb ` +- **Input File**: `./openapi/config.yml` +- **Process**: + 1. Read current version from config file + 2. Increment major/minor/patch based on input + 3. Write updated version back to config file + 4. Output new version for next steps +- **Example**: + - Current: 2.0.5 → Run with "minor" → New: 2.1.0 + +#### Step 2: Clean Repository +- **Script**: `ruby .github/clean.rb` +- **Process**: + 1. Delete all generated files from previous generation + 2. Protect certain directories from deletion (`.git`, `.github`, `openapi`, `LICENSE`, etc.) + 3. Keeps source configuration and workflow files intact + +#### Step 3: Generate SDK +- **Input**: OpenAPI specification from `https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/mx_platform_api.yml` +- **Output Directory**: `./latest/` +- **Configuration**: Uses `./openapi/config.yml` +- **Process**: + 1. Install OpenAPI Generator CLI globally + 2. Run generator with TypeScript-Axios language + 3. Copy documentation files to output directory + +#### Step 4: Create Feature Branch +- **Branch Name**: `openapi-generator-X.Y.Z` (version from step 1) +- **Process**: + 1. Create new branch from current checkout + 2. Stage all changes with `git add .` + 3. Commit with version number in message + +#### Step 5: Create Pull Request +- **Command**: `gh pr create -f` (uses commit message for PR title/body) +- **Destination**: Targets default branch (master) +- **Review**: PR is created and awaits manual review + merge + +#### Step 6: Trigger Publishing (After Merge) +- **Trigger**: When PR is merged to `master`, `on-push-master.yml` workflow activates +- **Condition**: Triggered only if files matching `latest/**` were modified +- **Workflows Called**: + 1. `./.github/workflows/publish.yml` + 2. `./.github/workflows/release.yml` +- **Result**: Same publishing and releasing as automatic flow + +--- + + + +## Supporting Scripts + +### version.rb +**Purpose**: Increment version numbers in configuration files + +**Usage**: `ruby .github/version.rb [config_file]` + +**Important Nuance - npmVersion as Source of Truth**: + +The `npmVersion` field in the config file is the **authoritative source of truth** for the package version. Here's how the version flows through the system: + +1. **Config File** (Source of Truth) + - `openapi/config.yml` contains `npmVersion: 2.0.0` + - This is the persistent, stored version number + - Lives in Git and is checked in with each update + +2. **version.rb Script** (Updates Source of Truth) + - Reads the current `npmVersion` from the config file + - Receives bump instruction from caller: "patch", "minor", or "major" + - Calculates new version: 2.0.0 → 2.0.1 (patch), 2.1.0 (minor), or 3.0.0 (major) + - **Writes updated npmVersion back to config file** (persists to Git) + - Outputs new version to stdout (for workflow logging) + +3. **package.mustache Template** (Uses Source of Truth) + - Contains placeholder: `"version": "{{npmVersion}}"` + - OpenAPI Generator replaces `{{npmVersion}}` with value from config file + - Generates `package.json` with the correct version number + +4. **Result** + - The generated `package.json` always has the correct version + - Version comes entirely from the config file + - No hardcoding in workflows or templates + +**Important Distinction**: +- `client_payload.version` from repository_dispatch is a **bump instruction** (e.g., "patch") +- `npmVersion` in config file is the **actual version number** (e.g., "2.0.0") +- These are different things! The bump instruction is used to calculate the new version number. + +**Behavior**: +- Reads YAML config file +- Parses current version (major.minor.patch) +- Increments requested component +- Resets lower components to 0 (e.g., 2.1.5 → 3.0.0 when major bumped) +- Writes updated config file +- Outputs new version to stdout + +**Config File Parameter**: Optional, defaults to `./openapi/config.yml` + +**Examples**: +```bash +ruby .github/version.rb patch # Bumps config.yml patch version (2.0.0 → 2.0.1) +ruby .github/version.rb minor openapi/config-v20111101.yml # Bumps config-v20111101 minor version (2.0.0 → 2.1.0) +ruby .github/version.rb major openapi/config-v20250224.yml # Bumps config-v20250224 major version (3.0.0 → 4.0.0) +``` + +### clean.rb +**Purpose**: Remove generated SDK files before regeneration + +**Behavior**: +- Walks through repository root directory +- Deletes all files/directories except those in ALLOW_LIST +- Protected directories: `.git`, `.github`, `.openapi-generator-ignore`, `openapi`, `LICENSE`, `README.md`, `CHANGELOG.md`, `MIGRATION.md` +- Prevents accidental deletion of configuration and workflow files + +**Part 5 Note**: When multi-version support is activated, protected list will include: `v20111101`, `v20250224`, and remove `latest` + +**Part 5 Note**: When multi-version support is activated, protected list will include: `v20111101`, `v20250224`, and remove `latest` + +--- + +## Configuration Files + +### openapi/config.yml + +```yaml +--- +generatorName: typescript-axios +npmName: mx-platform-node +npmVersion: 2.0.0 +supportsES6: true +.openapi-generator-ignore: true +``` + +**Used by**: +- `generate.yml` (manual generation) +- `generate_publish_release.yml` (automatic generation) +- `version.rb` script + +### openapi/templates/ +**Purpose**: Customized templates for package generation + +**Files**: +- `package.mustache`: Controls package.json generation + - **Key Feature**: Includes `"files"` field to explicitly control what gets published to npm + - Controls package name, version, scripts, dependencies +- `README.mustache`: Controls README.md generation + +--- + +## Path-Based Triggers + +### on-push-master.yml +**Purpose**: Automatically trigger publish and release workflows when SDK code changes are pushed to master + +```yaml +on: + push: + branches: [master] + paths: + - 'latest/**' # Only trigger on changes in the latest/ directory +``` + +**This prevents**: +- Enhancement PRs (docs only) from triggering publish +- README updates from triggering releases +- Workflow file changes from triggering publish + +--- + +## Workflow Sequences + +The following sequence diagrams show the timeline and interactions for each flow, making it clear when workflows trigger and what happens at each stage. + +### Flow 1: Automatic Generation (Repository Dispatch) + +```mermaid +sequenceDiagram + participant OpenAPI as OpenAPI
Repository + participant GH as GitHub
Actions + participant Gen as generate_publish
_release.yml + participant npm as npm
Registry + participant GHRel as GitHub
Releases + + OpenAPI->>GH: mx_platform_api.yml changes
(repository_dispatch event) + GH->>+Gen: Trigger workflow + Gen->>Gen: 1. Clean repo
(clean.rb) + Gen->>Gen: 2. Bump version
(version.rb) + Gen->>Gen: 3. Generate SDK
(OpenAPI Generator) + Gen->>Gen: 4. Copy docs
(LICENSE, CHANGELOG, MIGRATION) + Gen->>Gen: 5. Commit to master
(devexperience bot) + Gen->>npm: Dispatch publish_sdk event + Gen->>GHRel: Dispatch release_sdk event + deactivate Gen + + rect rgba(0, 255, 0, .1) + note right of npm: Parallel Publishing & Release + npm->>npm: publish.yml:
npm publish --tag next
from ./latest/ + GHRel->>GHRel: release.yml:
gh release create
with version tag + end + + npm-->>GH: ✅ Published + GHRel-->>GH: ✅ Released +``` + +### Flow 2: Manual Generation (Workflow Dispatch) + +```mermaid +sequenceDiagram + participant Dev as Developer + participant GH as GitHub
Actions + participant Gen as generate.yml + participant Review as Code
Review + participant Trigger as on-push-
master.yml + participant npm as npm
Registry + participant GHRel as GitHub
Releases + + Dev->>GH: Run generate.yml
(version_level: major/minor/patch) + GH->>+Gen: Trigger workflow + Gen->>Gen: 1. Bump version
(version.rb) + Gen->>Gen: 2. Clean repo
(clean.rb) + Gen->>Gen: 3. Generate SDK
(OpenAPI Generator) + Gen->>Gen: 4. Copy docs + Gen->>Gen: 5. Create feature branch
(openapi-generator-X.Y.Z) + Gen->>Gen: 6. Create Pull Request + deactivate Gen + + Review->>Review: 👤 Code Review + Review->>Review: Approve & Merge
to master + + GH->>+Trigger: on-push-master.yml
(path: latest/**) + Trigger->>Trigger: ✅ Path matched + Trigger->>npm: workflow_call publish.yml + Trigger->>GHRel: workflow_call release.yml + deactivate Trigger + + rect rgba(0, 255, 0, .1) + note right of npm: Parallel Publishing & Release + npm->>npm: publish.yml:
npm publish --tag next
from ./latest/ + GHRel->>GHRel: release.yml:
gh release create
with version tag + end + + npm-->>GH: ✅ Published + GHRel-->>GH: ✅ Released +``` + +--- + +--- + +## Environment Variables & Secrets Used + +### Required Secrets (`.github/secrets`) + +| Secret | Used In | Purpose | +|--------|---------|---------| +| `NPM_AUTH_TOKEN` | publish.yml | Authenticate to npm registry for publishing | +| `GITHUB_TOKEN` | All workflows | GitHub API access (auto-provided, but sometimes explicitly referenced) | +| `SLACK_WEBHOOK_URL` | All workflows | Send failure notifications to Slack | +| `PAPI_SDK_APP_ID` | generate_publish_release.yml | GitHub App ID for custom token generation | +| `PAPI_SDK_INSTALLATION_ID` | generate_publish_release.yml | GitHub App installation ID | +| `PAPI_SDK_PRIVATE_KEY` | generate_publish_release.yml | GitHub App private key | + +### Environment Setup + +- **Node**: v20.x +- **Ruby**: 3.1 +- **OpenAPI Generator**: Latest version (installed via npm during workflow) + +--- + +## Current Implementation Status + +### ✅ Fully Implemented +- Automatic generation from OpenAPI spec changes (Flow 1) +- Manual generation for PRs with version bumping (Flow 2) +- Path-based triggers for publish/release +- npm publishing with semantic versioning +- GitHub releases +- Slack notifications +- v2.0.0 stable release confirmed + +### Key Architectural Decisions + +1. **Direct Commit vs PR**: + - Automatic flow (Flow 1) commits directly to master + - Manual flow (Flow 2) creates PR for review + +2. **Tag Strategy**: + - `--tag next`: Used during auto-publish (for staging validation) + - Can be promoted to `latest` tag after validation + +3. **Path-Based Triggers**: Only changes to SDK code (`latest/**`) trigger publish/release, not docs or workflows + +4. **Atomic Operations**: Publishing and releasing happen in sequence within same workflow, preventing version mismatches + +--- + +## Troubleshooting + +### NPM Publish Fails +- Check `NPM_AUTH_TOKEN` secret is valid +- Verify token has publish permissions for `mx-platform-node` package +- Check version isn't already published + +### Release Creation Fails +- Verify `GITHUB_TOKEN` has release creation permissions +- Check if tag already exists (gh release fails if tag exists) + +### Generation Produces No Changes +- Verify OpenAPI spec URL is accessible +- Check openapi-generator-cli installed correctly +- Verify config file exists and is valid YAML + +### publish.yml or release.yml Don't Trigger After Generate +- Check path filter in `on-push-master.yml` matches changed files +- Verify files were actually committed (`git log` to confirm) +- Check branch is `master` and not another branch + +--- From 2a3471349061b40f0aff438e1ca114dccffb981b Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Mon, 26 Jan 2026 14:17:34 -0700 Subject: [PATCH 03/11] Update clean script to delete version directory only with arg --- .github/clean.rb | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/.github/clean.rb b/.github/clean.rb index 189d4b5..e7e65cf 100644 --- a/.github/clean.rb +++ b/.github/clean.rb @@ -1,26 +1,19 @@ require "fileutils" -ALLOW_LIST = [ - ".git", - ".github", - ".gitignore", - ".npmignore", - ".openapi-generator-ignore", - "CHANGELOG.md", - "LICENSE", - "MIGRATION.md", - "README.md", - "node_modules", - "openapi", - "openapitools.json", - "tmp" -].freeze +# Version-targeted deletion: Deletes specified version directory only +# All workflows must provide version directory parameter -::Dir.each_child(::Dir.pwd) do |source| - next if ALLOW_LIST.include?(source) +target_dir = ARGV[0] - # Preserve test-output directories for multi-version POC testing - next if source.start_with?("test-output-") +if target_dir.nil? || target_dir.empty? + raise "Error: Version directory parameter required. Usage: ruby clean.rb " +end - ::FileUtils.rm_rf("#{::Dir.pwd}/#{source}") +# Delete only the specified directory +target_path = "#{::Dir.pwd}/#{target_dir}" +if ::File.exist?(target_path) + ::FileUtils.rm_rf(target_path) + puts "Deleted: #{target_path}" +else + puts "Directory not found (will be created during generation): #{target_path}" end From 2b1ceb0f31ab76e99b46d9b7ee3f4f39301bcc4e Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Mon, 26 Jan 2026 14:27:49 -0700 Subject: [PATCH 04/11] Update version script to remove major and raise error if invalid version --- .github/version.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/version.rb b/.github/version.rb index d061278..87d9f3a 100644 --- a/.github/version.rb +++ b/.github/version.rb @@ -1,22 +1,22 @@ require "yaml" -# Support both single config and multi-version config approaches -# For multi-version POC, we can specify which config file to use -config_file = ARGV[1] || "openapi/config.yml" +# Default to config-v20111101 file if not provided for backwards compatibility +# This is because automated openapi repository dispatch currently only generates v20111101 +config_file = ARGV[1] || "openapi/config-v20111101.yml" config = ::YAML.load(::File.read(config_file)) major, minor, patch = config["npmVersion"].split(".") +# Note: "skip" logic is handled by workflow (version.rb not called when skip selected) +# Only minor and patch bumps are supported (major version locked to API version) case ARGV[0] -when "major" - major = major.succ - minor = 0 - patch = 0 when "minor" minor = minor.succ patch = 0 when "patch" patch = patch.succ +else + raise "Invalid version bump type: #{ARGV[0]}. Supported: 'minor' or 'patch'" end config["npmVersion"] = "#{major}.#{minor}.#{patch}" From 31e447e81b025776d410888770a11dcd1af33fc7 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 10:41:26 -0700 Subject: [PATCH 05/11] Add version directory variable to publish/release --- .github/workflows/publish.yml | 16 ++++++++++++---- .github/workflows/release.yml | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 26e32f4..10a0ca4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,10 +1,18 @@ name: Publish on: - repository_dispatch: - types: [publish_sdk] workflow_dispatch: + inputs: + version_directory: + description: 'Version directory to publish from' + required: true + type: string workflow_call: + inputs: + version_directory: + description: 'Version directory to publish from' + required: true + type: string jobs: Publish: @@ -16,10 +24,10 @@ jobs: node-version: "20.x" registry-url: "https://registry.npmjs.org" - name: Install and Publish - working-directory: ./latest + working-directory: ./${{ inputs.version_directory }} run: | npm install - npm publish --tag next + npm publish env: NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} - name: Slack notification diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 35ae98a..a4a1f9b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,18 @@ name: Release on: - repository_dispatch: - types: [release_sdk] + workflow_dispatch: + inputs: + version_directory: + description: 'Version directory to read version from' + required: true + type: string workflow_call: + inputs: + version_directory: + description: 'Version directory to read version from' + required: true + type: string jobs: Release: @@ -17,7 +26,7 @@ jobs: ruby-version: 3.1 - name: Read version id: read_version - run: echo "::set-output name=version::$(jq -r '.version' ./latest/package.json)" + run: echo "version=$(jq -r '.version' ./${{ inputs.version_directory }}/package.json)" >> $GITHUB_OUTPUT - name: Create tag and release run: | gh release create "v${{ steps.read_version.outputs.version }}" From acec9a12cf88129823f5beaddee493b3de63e3a2 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 10:42:15 -0700 Subject: [PATCH 06/11] Update on push to do matrix style versioned publish/release, skip-publish flag --- .github/workflows/on-push-master.yml | 54 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/.github/workflows/on-push-master.yml b/.github/workflows/on-push-master.yml index d064f38..4c8a300 100644 --- a/.github/workflows/on-push-master.yml +++ b/.github/workflows/on-push-master.yml @@ -4,14 +4,58 @@ on: push: branches: [master] paths: - # Latest version SDK files - - 'latest/**' + - 'v20111101/**' + - 'v20250224/**' jobs: - Publish: + # Check for skip-publish flag in commit message. This allows skipping publish/release for specific scenarios, + # such as testing generated code, migrating files to new paths, etc. + check-skip-publish: + runs-on: ubuntu-latest + outputs: + skip_publish: ${{ steps.check.outputs.skip_publish }} + steps: + - name: Check for [skip-publish] flag in commit message + id: check + run: | + COMMIT_MSG="${{ github.event.head_commit.message }}" + if [[ "$COMMIT_MSG" == *"[skip-publish]"* ]]; then + echo "skip_publish=true" >> $GITHUB_OUTPUT + echo "🚫 [skip-publish] flag detected - skipping all publish/release jobs" + else + echo "skip_publish=false" >> $GITHUB_OUTPUT + echo "✅ No skip flag - proceeding with publish/release" + fi + + # Matrix-based publish and release: runs one job per version, + # conditionally based on path changes + # Each matrix iteration only executes if both conditions are true: + # 1. [skip-publish] flag is NOT present in commit message + # 2. Files in this version's directory were modified in the commit + publish: + needs: check-skip-publish + strategy: + matrix: + version: + - api_version: v20111101 + - api_version: v20250224 + fail-fast: false + if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, matrix.version.api_version) uses: ./.github/workflows/publish.yml + with: + version_directory: ${{ matrix.version.api_version }} secrets: inherit - - Release: + + release: + needs: [check-skip-publish, publish] + strategy: + matrix: + version: + - api_version: v20111101 + - api_version: v20250224 + fail-fast: false + if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, matrix.version.api_version) uses: ./.github/workflows/release.yml + with: + version_directory: ${{ matrix.version.api_version }} secrets: inherit From a0ea3d75c73879b686f03c003b278a1cfe261dae Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 13:23:32 -0700 Subject: [PATCH 07/11] Generate to validate bump version, skip bump, matrix for multi version, update changelog --- .github/workflows/generate.yml | 203 ++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 57 deletions(-) diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 1c4f2bc..b0448a1 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -3,69 +3,158 @@ name: Generate on: workflow_dispatch: inputs: - version_level: - description: "Bump version" + api_version: + description: "API version to generate" required: true - default: "patch" type: choice options: - - major - - minor - - patch + - v20111101 + - v20250224 + version_bump: + description: "Version bump type" + required: true + default: "skip" + type: choice + options: + - skip + - minor + - patch jobs: + Validate: + runs-on: ubuntu-latest + outputs: + config_file: ${{ steps.validate.outputs.config_file }} + spec_url: ${{ steps.validate.outputs.spec_url }} + steps: + - uses: actions/checkout@v3 + - name: Validate configuration + id: validate + run: | + API_VERSION="${{ github.event.inputs.api_version }}" + CONFIG_FILE="openapi/config-${API_VERSION}.yml" + # Versioned spec URLs (manual workflow uses 'master' branch) + # Note: Manual workflow doesn't need commit SHA since developer controls timing + # CDN cache race condition only affects automated repository_dispatch triggers + # v20111101 -> https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/v20111101.yml + # v20250224 -> https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/v20250224.yml + SPEC_URL="https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/${API_VERSION}.yml" + + # Check config file exists + if [ ! -f "$CONFIG_FILE" ]; then + echo "❌ Config file not found: $CONFIG_FILE" + exit 1 + fi + + # Validate semantic versioning (major must match API version) + CURRENT_VERSION=$(grep 'npmVersion' "$CONFIG_FILE" | cut -d':' -f2 | tr -d ' ') + MAJOR_VERSION=$(echo "$CURRENT_VERSION" | cut -d'.' -f1) + + if [ "$API_VERSION" = "v20111101" ] && [ "$MAJOR_VERSION" != "2" ]; then + echo "❌ Semantic versioning error: v20111101 must have major version 2, found $MAJOR_VERSION" + exit 1 + fi + + if [ "$API_VERSION" = "v20250224" ] && [ "$MAJOR_VERSION" != "3" ]; then + echo "❌ Semantic versioning error: v20250224 must have major version 3, found $MAJOR_VERSION" + exit 1 + fi + + echo "✅ Validation passed" + echo "config_file=$CONFIG_FILE" >> $GITHUB_OUTPUT + echo "spec_url=$SPEC_URL" >> $GITHUB_OUTPUT + Generate: runs-on: ubuntu-latest + needs: Validate steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.1 - - name: Bump version - id: bump_version - run: echo "::set-output name=version::$(ruby .github/version.rb ${{ github.event.inputs.version_level }})" - - name: Clean repo - run: ruby .github/clean.rb - - name: Install openapi-generator-cli and Generate SDK - run: | - npm install @openapitools/openapi-generator-cli -g - - run: | - openapi-generator-cli generate \ - -i https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/mx_platform_api.yml \ - -g typescript-axios \ - -c ./openapi/config.yml \ - -t ./openapi/templates \ - -o ./latest - - name: Copy documentation to latest - run: | - cp LICENSE ./latest/LICENSE - cp CHANGELOG.md ./latest/CHANGELOG.md - cp MIGRATION.md ./latest/MIGRATION.md - - name: Create branch - run: git checkout -b "openapi-generator-${{ steps.bump_version.outputs.version }}" - - name: Create commit - run: | - git config user.name "devexperience" - git config user.email "devexperience@mx.com" - git add . - git commit -m "Generated version ${{ steps.bump_version.outputs.version }} + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.1 + - name: Bump version + id: bump_version + run: | + if [ "${{ github.event.inputs.version_bump }}" != "skip" ]; then + NEW_VERSION=$(ruby .github/version.rb ${{ github.event.inputs.version_bump }} ${{ needs.Validate.outputs.config_file }}) + else + NEW_VERSION=$(jq -r '.version' ./${{ github.event.inputs.api_version }}/package.json 2>/dev/null || grep 'npmVersion' ${{ needs.Validate.outputs.config_file }} | cut -d':' -f2 | tr -d ' ') + fi + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "📦 Version: $NEW_VERSION" + - name: Clean repo + run: ruby .github/clean.rb ${{ github.event.inputs.api_version }} + - name: Copy generator ignore rules + run: cp .openapi-generator-ignore ./${{ github.event.inputs.api_version }}/ + - name: Install openapi-generator-cli and Generate SDK + run: npm install @openapitools/openapi-generator-cli -g + - name: Generate SDK + run: | + openapi-generator-cli generate \ + -i ${{ needs.Validate.outputs.spec_url }} \ + -g typescript-axios \ + -c ${{ needs.Validate.outputs.config_file }} \ + -t ./openapi/templates \ + -o ./${{ github.event.inputs.api_version }} + - name: Update CHANGELOG + run: | + VERSION=$(jq -r '.version' ./${{ github.event.inputs.api_version }}/package.json) + DATE=$(date +%Y-%m-%d) + + # Find the line number of the first version entry (first line starting with ##) + FIRST_ENTRY_LINE=$(grep -n "^##" CHANGELOG.md | head -1 | cut -d: -f1) + + # Extract header (everything before first entry) + head -n $((FIRST_ENTRY_LINE - 1)) CHANGELOG.md > /tmp/new_changelog.txt + + # Add new entry + cat >> /tmp/new_changelog.txt << EOF + + ## [$VERSION] - $DATE (${{ github.event.inputs.api_version }} API) + Updated ${{ github.event.inputs.api_version }} API specification. + [See full API changelog](https://docs.mx.com/resources/changelog/platform) + EOF + + # Add rest of file (from first entry onwards) + tail -n +$FIRST_ENTRY_LINE CHANGELOG.md >> /tmp/new_changelog.txt + + # Replace original + mv /tmp/new_changelog.txt CHANGELOG.md + - name: Copy documentation + run: | + cp LICENSE ./${{ github.event.inputs.api_version }}/LICENSE + cp CHANGELOG.md ./${{ github.event.inputs.api_version }}/CHANGELOG.md + cp MIGRATION.md ./${{ github.event.inputs.api_version }}/MIGRATION.md + - name: Create branch + run: git checkout -b "sdk/generate-api-${{ github.event.inputs.api_version }}-${{ steps.bump_version.outputs.version }}" + - name: Create commit + run: | + git config user.name "devexperience" + git config user.email "devexperience@mx.com" + git add . + git commit -m "Generated API ${{ github.event.inputs.api_version }} SDK for version ${{ steps.bump_version.outputs.version }} - This pull request was automatically generated by a GitHub Action to generate version ${{ steps.bump_version.outputs.version }} of this library." - git push -u origin "openapi-generator-${{ steps.bump_version.outputs.version }}" - - name: Create PR - run: gh pr create -f - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Slack notification - uses: ravsamhq/notify-slack-action@v2 - if: always() - with: - status: ${{ job.status }} - token: ${{ secrets.GITHUB_TOKEN }} - notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" - notify_when: "failure" - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + This pull request was automatically generated by a GitHub Action. + + API Version: ${{ github.event.inputs.api_version }} + SDK Version: ${{ steps.bump_version.outputs.version }} + Version Bump: ${{ github.event.inputs.version_bump }} + ${{ github.event.inputs.version_bump == 'skip' && '⚠️ NO VERSION BUMP - This is a review-only generation for validation before release.' || '' }}" + git push -u origin "sdk/generate-api-${{ github.event.inputs.api_version }}-${{ steps.bump_version.outputs.version }}" + - name: Create PR + run: gh pr create -f + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Slack notification + uses: ravsamhq/notify-slack-action@v2 + if: always() + with: + status: ${{ job.status }} + token: ${{ secrets.GITHUB_TOKEN }} + notification_title: "{repo}: {workflow} workflow" + message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" + footer: "<{workflow_url}|View Workflow>" + notify_when: "failure" + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} From 31004795595f7ef3fb4ed37bb957d0bc86dbc244 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 14:26:35 -0700 Subject: [PATCH 08/11] Update automation to accept new variables, matrix for multi version, update changelog --- .../workflows/generate_publish_release.yml | 188 +++++++++++++++--- 1 file changed, 161 insertions(+), 27 deletions(-) diff --git a/.github/workflows/generate_publish_release.yml b/.github/workflows/generate_publish_release.yml index 10832e6..4211d57 100644 --- a/.github/workflows/generate_publish_release.yml +++ b/.github/workflows/generate_publish_release.yml @@ -4,9 +4,53 @@ on: repository_dispatch: types: [generate_publish_release] +env: + # Default to v20111101 only for backwards compatibility + # When openapi repo sends api_versions, use that instead + VERSIONS_TO_GENERATE: ${{ github.event.client_payload.api_versions || 'v20111101' }} + jobs: + Setup: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Set up matrix + id: set-matrix + run: | + VERSIONS="${{ env.VERSIONS_TO_GENERATE }}" + echo "Versions to generate: $VERSIONS" + + # Build matrix JSON + MATRIX_JSON='{"include":[' + FIRST=true + + for VERSION in $(echo $VERSIONS | tr ',' ' '); do + if [ "$FIRST" = false ]; then + MATRIX_JSON+=',' + fi + FIRST=false + + # Map version to config file and major version + if [ "$VERSION" = "v20111101" ]; then + CONFIG="openapi/config-v20111101.yml" + elif [ "$VERSION" = "v20250224" ]; then + CONFIG="openapi/config-v20250224.yml" + fi + + MATRIX_JSON+="{\"api_version\":\"$VERSION\",\"config_file\":\"$CONFIG\"}" + done + + MATRIX_JSON+=']}' + echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT + echo "Matrix: $MATRIX_JSON" + Generate: runs-on: ubuntu-latest + needs: Setup + strategy: + matrix: ${{ fromJson(needs.Setup.outputs.matrix) }} + fail-fast: false steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 @@ -17,24 +61,114 @@ jobs: ruby-version: 3.1 - name: Bump version id: bump_version - run: echo "::set-output name=version::$(ruby .github/version.rb ${{ github.event.client_payload.version }})" + run: | + NEW_VERSION=$(ruby .github/version.rb ${{ github.event.client_payload.version || 'patch' }} ${{ matrix.config_file }}) + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - name: Clean repo - run: ruby .github/clean.rb + run: ruby .github/clean.rb ${{ matrix.api_version }} + - name: Copy generator ignore rules + run: cp .openapi-generator-ignore ./${{ matrix.api_version }}/ - name: Install openapi-generator-cli + run: npm install @openapitools/openapi-generator-cli -g + - name: Generate SDK run: | - npm install @openapitools/openapi-generator-cli -g - - run: | + # Versioned spec URLs with commit SHA to avoid GitHub CDN cache race condition + # Problem: GitHub's raw.githubusercontent.com CDN caches files for 5 minutes + # If openapi repo commits and immediately triggers this workflow, CDN may serve stale spec + # Solution: Use commit SHA in URL to bypass cache and guarantee correct spec version + # Falls back to 'master' if openapi doesn't send commit_sha openapi-generator-cli generate \ - -i https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/mx_platform_api.yml \ + -i https://raw.githubusercontent.com/mxenabled/openapi/${{ github.event.client_payload.commit_sha || 'master' }}/openapi/${{ matrix.api_version }}.yml \ -g typescript-axios \ - -c ./openapi/config.yml \ + -c ${{ matrix.config_file }} \ -t ./openapi/templates \ - -o ./latest - - name: Copy documentation to latest + -o ./${{ matrix.api_version }} + - name: Copy documentation + run: | + cp LICENSE ./${{ matrix.api_version }}/LICENSE + cp CHANGELOG.md ./${{ matrix.api_version }}/CHANGELOG.md + cp MIGRATION.md ./${{ matrix.api_version }}/MIGRATION.md + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: generated-${{ matrix.api_version }} + path: ./${{ matrix.api_version }} + + Commit-and-Push: + runs-on: ubuntu-latest + needs: [Setup, Generate] + steps: + - uses: actions/checkout@v3 + - name: Download all artifacts + uses: actions/download-artifact@v3 + with: + path: ./generated + - name: Move generated files and track versions + id: track_versions + run: | + GENERATED_VERSIONS="" + + for dir in ./generated/generated-*; do + VERSION=$(basename "$dir" | sed 's/generated-//') + mv "$dir" "./$VERSION" + GENERATED_VERSIONS="$GENERATED_VERSIONS $VERSION" + done + + echo "generated_versions=$GENERATED_VERSIONS" >> $GITHUB_OUTPUT + - name: Update CHANGELOG run: | - cp LICENSE ./latest/LICENSE - cp CHANGELOG.md ./latest/CHANGELOG.md - cp MIGRATION.md ./latest/MIGRATION.md + GENERATED_VERSIONS="${{ steps.track_versions.outputs.generated_versions }}" + DATE=$(date +%Y-%m-%d) + + # Only update if something was generated + if [ -z "$GENERATED_VERSIONS" ]; then + exit 0 + fi + + # Initialize version variables as empty + V20111101_VERSION="" + V20250224_VERSION="" + + # Read versions only for versions that were actually generated + for VERSION in $GENERATED_VERSIONS; do + if [ "$VERSION" = "v20111101" ]; then + V20111101_VERSION=$(jq -r '.version' ./v20111101/package.json 2>/dev/null) + elif [ "$VERSION" = "v20250224" ]; then + V20250224_VERSION=$(jq -r '.version' ./v20250224/package.json 2>/dev/null) + fi + done + + # Find the line number of the first version entry (first line starting with ##) + FIRST_ENTRY_LINE=$(grep -n "^##" CHANGELOG.md | head -1 | cut -d: -f1) + + # Extract header (everything before first entry) + head -n $((FIRST_ENTRY_LINE - 1)) CHANGELOG.md > /tmp/new_changelog.txt + + # Build and add changelog entries ONLY for versions that were actually generated + # v20250224 first (newer API version), then v20111101 + if [ ! -z "$V20250224_VERSION" ]; then + cat >> /tmp/new_changelog.txt << EOF + + ## [$V20250224_VERSION] - $DATE (v20250224 API) + Updated v20250224 API specification. + [See full API changelog](https://docs.mx.com/resources/changelog/platform) + EOF + fi + + if [ ! -z "$V20111101_VERSION" ]; then + cat >> /tmp/new_changelog.txt << EOF + + ## [$V20111101_VERSION] - $DATE (v20111101 API) + Updated v20111101 API specification. + [See full API changelog](https://docs.mx.com/resources/changelog/platform) + EOF + fi + + # Add rest of file (from first entry onwards) + tail -n +$FIRST_ENTRY_LINE CHANGELOG.md >> /tmp/new_changelog.txt + + # Replace original + mv /tmp/new_changelog.txt CHANGELOG.md - name: Checkout master run: git checkout master - name: Create commit @@ -42,30 +176,30 @@ jobs: git config user.name "devexperience" git config user.email "devexperience@mx.com" git add . - git commit -m "Generated version ${{ steps.bump_version.outputs.version }} + git commit -m "Generated SDK versions: ${{ env.VERSIONS_TO_GENERATE }} - This commit was automatically created by a GitHub Action to generate version ${{ steps.bump_version.outputs.version }} of this library." + This commit was automatically created by a GitHub Action." - name: Push to master run: git push origin master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Generate access token - id: generate_token - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.PAPI_SDK_APP_ID }} - installation_id: ${{ secrets.PAPI_SDK_INSTALLATION_ID }} - private_key: ${{ secrets.PAPI_SDK_PRIVATE_KEY }} + + Publish-and-Release: + runs-on: ubuntu-latest + needs: [Setup, Commit-and-Push] + strategy: + matrix: ${{ fromJson(needs.Setup.outputs.matrix) }} + steps: - name: Publish - uses: peter-evans/repository-dispatch@v2 + uses: ./.github/workflows/publish.yml with: - token: ${{ steps.generate_token.outputs.token }} - event-type: publish_sdk + version_directory: ${{ matrix.api_version }} + secrets: inherit - name: Release - uses: peter-evans/repository-dispatch@v2 + uses: ./.github/workflows/release.yml with: - token: ${{ steps.generate_token.outputs.token }} - event-type: release_sdk + version_directory: ${{ matrix.api_version }} + secrets: inherit - name: Slack notification uses: ravsamhq/notify-slack-action@v2 if: always() @@ -73,7 +207,7 @@ jobs: status: ${{ job.status }} token: ${{ secrets.GITHUB_TOKEN }} notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" + message_format: "{emoji} Generated and published ${{ matrix.api_version }}" footer: "<{workflow_url}|View Workflow>" notify_when: "failure" env: From 99970ea1bcc1c8a52869d4f0680bc312c85c525c Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 15:00:43 -0700 Subject: [PATCH 09/11] Update all the md docs and templates accordingly --- MIGRATION.md | 32 +++++++++ README.md | 103 +++++++++-------------------- openapi/config-v20111101.yml | 1 + openapi/config-v20250224.yml | 1 + openapi/templates/README.mustache | 40 ++++++++++- openapi/templates/package.mustache | 7 +- 6 files changed, 109 insertions(+), 75 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index c77937e..5ac2994 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,5 +1,37 @@ # Migration Guide +## Upgrading from v20111101 (v2.x) to v20250224 (v3.x) + +The v20250224 API is now available, and v3.0.0 of this SDK provides support as an independent major version. + +### Installation + +The two API versions are published as separate major versions of the same npm package: + +**For v20111101 API:** +```bash +npm install mx-platform-node@^2 +``` + +**For v20250224 API:** +```bash +npm install mx-platform-node@^3 +``` + +### Migration Path + +1. **Review API Changes**: Consult the [MX Platform API Migration Guide](https://docs.mx.com/api-reference/platform-api/overview/migration) for breaking changes and new features +2. **Update Package**: Update your `package.json` to use `mx-platform-node@^3` +3. **Update Imports**: Both APIs have similar structure, but review type definitions for any breaking changes +4. **Run Tests**: Validate your code works with the new SDK version +5. **Deploy**: Update production once validated + +### Benefits of TypeScript + +Since this is a TypeScript SDK, the compiler will help catch most compatibility issues at compile time when you update to v3.x. + +--- + ## Upgrading to v2.0.0 from v1.10.0 or earlier ### Breaking Change: API Class Restructure diff --git a/README.md b/README.md index 777ca83..891801b 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,55 @@ *This project is currently in **Beta**. Please open up an issue [here](https://github.com/mxenabled/mx-platform-node/issues) to report issues using the MX Platform Node.js library.* -# MX Platform Node.js +# MX Platform Node.js SDK -The [MX Platform API](https://www.mx.com/products/platform-api) is a powerful, fully-featured API designed to make aggregating and enhancing financial data easy and reliable. It can seamlessly connect your app or website to tens of thousands of financial institutions. +This repository contains the Node.js SDK for the [MX Platform API](https://www.mx.com/products/platform-api). The SDK supports multiple API versions, published as independent major versions of the same npm package. -## Documentation +## Which API Version Do You Need? -Examples for the API endpoints can be found [here.](https://docs.mx.com/api) - -## Requirements - -The generated Node module can be used in the following environments: - -Environment -* Node.js -* Webpack -* Browserify - -Language level -* ES5 - you must have a Promises/A+ library installed -* ES6 - -Module system -* CommonJS -* ES6 module system +| API Version | npm Package | Documentation | +|---|---|---| +| **v20111101** | `mx-platform-node@^2` | [v20111101 SDK README](./v20111101/README.md) | +| **v20250224** | `mx-platform-node@^3` | [v20250224 SDK README](./v20250224/README.md) | ## Installation -To build and compile the TypeScript sources to JavaScript use: +```bash +# For v20111101 API +npm install mx-platform-node@^2 -```shell -npm install mx-platform-node +# For v20250224 API +npm install mx-platform-node@^3 ``` -## Getting Started - -In order to make requests, you will need to [sign up](https://dashboard.mx.com/sign_up) for the MX Platform API and get a `Client ID` and `API Key`. - -Please follow the [installation](#installation) procedure and then run the following code to create your first User: +## API Migration -```javascript -import { Configuration, UsersApi } from 'mx-platform-node'; +If you're upgrading from v20111101 to v20250224, see the [MX Platform API Migration Guide](https://docs.mx.com/api-reference/platform-api/overview/migration). -const configuration = new Configuration({ - // Configure with your Client ID/API Key from https://dashboard.mx.com - username: 'Your Client ID', - password: 'Your API Key', +## Repository Structure - // Configure environment. https://int-api.mx.com for development, https://api.mx.com for production - basePath: 'https://int-api.mx.com', +This repository uses [OpenAPI Generator](https://openapi-generator.tech) to automatically generate TypeScript SDKs from OpenAPI specifications. - baseOptions: { - headers: { - Accept: 'application/vnd.mx.api.v1+json' - } - } -}); - -const usersApi = new UsersApi(configuration); - -const requestBody = { - user: { - metadata: 'Creating a user!' - } -}; - -const response = await usersApi.createUser(requestBody); - -console.log(response.data); +``` +v20111101/ # Generated SDK for v20111101 API +v20250224/ # Generated SDK for v20250224 API +openapi/ # SDK generation configuration and templates +.github/workflows/ # Automation for generation, publishing, and releasing +docs/ # Repository documentation and contribution guidelines ``` -## Upgrading from v1.x? - -> **⚠️ Breaking Changes in v2.0.0:** If you're upgrading from v1.10.0 or earlier, the API structure has changed significantly. See the [Migration Guide](MIGRATION.md) for detailed instructions on updating your code. +## For Contributors -## Development +For detailed information about: +- How the SDK generation process works +- How to contribute to this repository +- Publishing and release workflows +- Architecture and design decisions -This project was generated by the [OpenAPI Generator](https://openapi-generator.tech). To generate this library, verify you have the latest version of the `openapi-generator-cli` found [here.](https://github.com/OpenAPITools/openapi-generator#17---npm) +Please see the [docs/](./docs/) directory. -Running the following command in this repo's directory will generate this library using the [MX Platform API OpenAPI spec](https://github.com/mxenabled/openapi/blob/master/openapi/mx_platform_api.yml) with our [configuration and templates.](https://github.com/mxenabled/mx-platform-ruby/tree/master/openapi) -```shell -openapi-generator-cli generate \ --i https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/mx_platform_api.yml \ --g typescript-axios \ --c ./openapi/config.yml \ --t ./openapi/templates -``` +## Support -## Contributing +- **SDK Issues**: [Open an issue](https://github.com/mxenabled/mx-platform-node/issues) +- **API Documentation**: [MX Platform API Docs](https://docs.mx.com) +- **API Changelog**: [MX Platform Changelog](https://docs.mx.com/resources/changelog/platform) -Please [open an issue](https://github.com/mxenabled/mx-platform-node/issues) or [submit a pull request.](https://github.com/mxenabled/mx-platform-node/pulls) diff --git a/openapi/config-v20111101.yml b/openapi/config-v20111101.yml index f4caae4..2c8fe1d 100644 --- a/openapi/config-v20111101.yml +++ b/openapi/config-v20111101.yml @@ -1,4 +1,5 @@ --- +apiVersion: v20111101 generatorName: typescript-axios npmName: mx-platform-node npmVersion: 2.0.0 diff --git a/openapi/config-v20250224.yml b/openapi/config-v20250224.yml index 8184260..a4fa35c 100644 --- a/openapi/config-v20250224.yml +++ b/openapi/config-v20250224.yml @@ -1,4 +1,5 @@ --- +apiVersion: v20250224 generatorName: typescript-axios npmName: mx-platform-node npmVersion: 3.0.0 diff --git a/openapi/templates/README.mustache b/openapi/templates/README.mustache index 777ca83..6c1c1fb 100644 --- a/openapi/templates/README.mustache +++ b/openapi/templates/README.mustache @@ -1,6 +1,44 @@ *This project is currently in **Beta**. Please open up an issue [here](https://github.com/mxenabled/mx-platform-node/issues) to report issues using the MX Platform Node.js library.* -# MX Platform Node.js +# MX Platform Node.js ({{apiVersion}} API) + +**SDK version:** {{npmVersion}} +**API version:** {{apiVersion}} + +You are using the **{{apiVersion}}** API version of `mx-platform-node`. For other API versions, see [Available API Versions](#available-api-versions) below. + +### Checking Your Installed Version + +To verify which API version you have installed: + +**In package.json:** +```json +{ + "dependencies": { + "mx-platform-node": "^{{npmVersion}}" + } +} +``` + +**Programmatically in your code:** +```javascript +const pkg = require('mx-platform-node/package.json'); +console.log(pkg.apiVersion); // {{apiVersion}} +``` + +**Via npm:** +```shell +npm view mx-platform-node@{{npmVersion}} +``` + +## Available API Versions + +- **{{npmName}}@2.x.x** - [v20111101 API](https://docs.mx.com/api-reference/platform-api/v20111101/reference/mx-platform-api/) +- **{{npmName}}@3.x.x** - [v20250224 API](https://docs.mx.com/api-reference/platform-api/reference/mx-platform-api/) + +--- + +## Overview The [MX Platform API](https://www.mx.com/products/platform-api) is a powerful, fully-featured API designed to make aggregating and enhancing financial data easy and reliable. It can seamlessly connect your app or website to tens of thousands of financial institutions. diff --git a/openapi/templates/package.mustache b/openapi/templates/package.mustache index b1334f2..9c81cd9 100644 --- a/openapi/templates/package.mustache +++ b/openapi/templates/package.mustache @@ -1,7 +1,8 @@ { "name": "{{npmName}}", "version": "{{npmVersion}}", - "description": "A Node library for the MX Platform API.", + "description": "A Node.js SDK for the MX Platform API ({{apiVersion}})", + "apiVersion": "{{apiVersion}}", "author": "MX", "keywords": [ "mx", @@ -14,9 +15,7 @@ "typings": "./dist/index.d.ts", "files": [ "dist/", - "CHANGELOG.md", - "README.md", - "MIGRATION.md" + "*.md" ], "scripts": { "build": "tsc --outDir dist/", From d524cec48fcdf3a45fa497251dbe6d0f8a0732c0 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 15:31:00 -0700 Subject: [PATCH 10/11] Create all the docs....soooo many docs --- .github/workflows/generate-multi-version.yml | 149 ----- .github/workflows/test-multi-version.yml | 152 ----- docs/Adding-a-New-API-Version.md | 302 ++++++++++ docs/Multi-Version-SDK-Flow.md | 241 ++++++++ docs/SDK-Generation-Publishing-Flow.md | 17 +- docs/Troubleshooting-Guide.md | 384 ++++++++++++ docs/Workflow-and-Configuration-Reference.md | 581 +++++++++++++++++++ 7 files changed, 1521 insertions(+), 305 deletions(-) delete mode 100644 .github/workflows/generate-multi-version.yml delete mode 100644 .github/workflows/test-multi-version.yml create mode 100644 docs/Adding-a-New-API-Version.md create mode 100644 docs/Multi-Version-SDK-Flow.md create mode 100644 docs/Troubleshooting-Guide.md create mode 100644 docs/Workflow-and-Configuration-Reference.md diff --git a/.github/workflows/generate-multi-version.yml b/.github/workflows/generate-multi-version.yml deleted file mode 100644 index f5b7491..0000000 --- a/.github/workflows/generate-multi-version.yml +++ /dev/null @@ -1,149 +0,0 @@ -name: Generate Multi-Version SDK - -on: - workflow_dispatch: - inputs: - api_version: - description: 'API Version to generate' - required: true - default: 'v20111101' - type: choice - options: - - 'v20111101' - - 'v20250224' - - 'latest' - version_level: - description: "Bump version" - required: true - default: "patch" - type: choice - options: - - major - - minor - - patch - -jobs: - Generate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "20" - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.1 - - # Determine configuration based on API version - - name: Set version configuration - id: config - run: | - API_VERSION="${{ github.event.inputs.api_version }}" - - echo "config_file=./openapi/config-$API_VERSION.yml" >> $GITHUB_OUTPUT - - if [ "$API_VERSION" = "latest" ]; then - echo "spec_url=https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/v20111101.yml" >> $GITHUB_OUTPUT - echo "output_dir=." >> $GITHUB_OUTPUT - else - echo "spec_url=https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/$API_VERSION.yml" >> $GITHUB_OUTPUT - echo "output_dir=./$API_VERSION" >> $GITHUB_OUTPUT - fi - - echo "branch_suffix=-$API_VERSION" >> $GITHUB_OUTPUT - - - name: Bump version - id: bump_version - run: echo "version=$(ruby .github/version.rb ${{ github.event.inputs.version_level }} ${{ steps.config.outputs.config_file }})" >> $GITHUB_OUTPUT - - # Note: Do NOT clean repo for multi-version - we want to preserve existing version directories - # The clean.rb script already protects version directories (v20111101, v20250224) - - - name: Install openapi-generator-cli - run: | - npm install @openapitools/openapi-generator-cli -g - - # Validate config file exists - - name: Validate config file - run: | - if [ ! -f "${{ steps.config.outputs.config_file }}" ]; then - echo "❌ Config file ${{ steps.config.outputs.config_file }} not found" - echo "Available config files:" - ls -la ./openapi/config*.yml || echo "No config files found" - exit 1 - fi - echo "✅ Using config file: ${{ steps.config.outputs.config_file }}" - - - name: Generate SDK - run: | - echo "🔧 Generating SDK for version: ${{ github.event.inputs.api_version }}" - echo "📄 Config: ${{ steps.config.outputs.config_file }}" - echo "🌐 Spec: ${{ steps.config.outputs.spec_url }}" - echo "📁 Output: ${{ steps.config.outputs.output_dir }}" - - openapi-generator-cli generate \ - -i ${{ steps.config.outputs.spec_url }} \ - -g typescript-axios \ - -c ${{ steps.config.outputs.config_file }} \ - -t ./openapi/templates \ - -o ${{ steps.config.outputs.output_dir }} - - # Test TypeScript compilation - - name: Test TypeScript compilation - run: | - cd ${{ steps.config.outputs.output_dir }} - npm install - npm run build - echo "✅ TypeScript compilation successful" - - - name: Get package info - id: package_info - run: | - PACKAGE_NAME=$(cat ${{ steps.config.outputs.output_dir }}/package.json | grep '"name"' | cut -d'"' -f4) - echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT - - - name: Create branch - run: git checkout -b "openapi-generator-${{ steps.bump_version.outputs.version }}${{ steps.config.outputs.branch_suffix }}" - - - name: Create commit - run: | - git config user.name "devexperience" - git config user.email "devexperience@mx.com" - git add . - git commit -m "Generated version ${{ steps.bump_version.outputs.version }} (${{ github.event.inputs.api_version }}) - - This pull request was automatically generated by a GitHub Action to generate version ${{ steps.bump_version.outputs.version }} of this library using API version ${{ github.event.inputs.api_version }}." - git push -u origin "openapi-generator-${{ steps.bump_version.outputs.version }}${{ steps.config.outputs.branch_suffix }}" - - - name: Create PR - run: | - gh pr create \ - --title "Generated version ${{ steps.bump_version.outputs.version }} (${{ github.event.inputs.api_version }})" \ - --body "This pull request was automatically generated using API version **${{ github.event.inputs.api_version }}**. - - ## Generation Details - - 📄 **Config**: \`${{ steps.config.outputs.config_file }}\` - - 🌐 **Spec**: \`${{ steps.config.outputs.spec_url }}\` - - 🔢 **Version**: ${{ steps.bump_version.outputs.version }} - - 📦 **Package name**: ${{ steps.package_info.outputs.package_name }} - - ✅ **TypeScript compilation**: Passed - - ## Testing Notes - This is a multi-version SDK generation for testing purposes. The generated package uses a version-specific name to avoid conflicts with the production package. - - Please review the generated changes before merging." - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Slack notification - uses: ravsamhq/notify-slack-action@v2 - if: always() - with: - status: ${{ job.status }} - token: ${{ secrets.GITHUB_TOKEN }} - notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" - notify_when: "failure" - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/test-multi-version.yml b/.github/workflows/test-multi-version.yml deleted file mode 100644 index e80fd13..0000000 --- a/.github/workflows/test-multi-version.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: Test Multi-Version SDK - -on: - workflow_dispatch: - inputs: - api_version: - description: 'API Version to generate' - required: true - default: 'v20111101' - type: choice - options: - - 'v20111101' - - 'v20250224' - - 'latest' - test_level: - description: 'Testing level' - required: true - default: 'generate_only' - type: choice - options: - - 'generate_only' # No commits, no publishing - - 'github_packages' # Publish to GitHub Packages (safe staging) - -jobs: - Test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "20" - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.1 - - # Determine configuration based on API version - - name: Set version configuration - id: config - run: | - API_VERSION="${{ github.event.inputs.api_version }}" - - echo "config_file=./openapi/config-$API_VERSION.yml" >> $GITHUB_OUTPUT - echo "output_dir=./test-output-$API_VERSION" >> $GITHUB_OUTPUT - - if [ "$API_VERSION" = "latest" ]; then - echo "spec_url=https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/v20111101.yml" >> $GITHUB_OUTPUT - else - echo "spec_url=https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/$API_VERSION.yml" >> $GITHUB_OUTPUT - fi - - # Create output directory for testing versions - - name: Prepare test output directory - run: mkdir -p ${{ steps.config.outputs.output_dir }} - - # Install OpenAPI Generator - - name: Install openapi-generator-cli - run: | - npm install @openapitools/openapi-generator-cli -g - - # Validate config file exists - - name: Validate config file - run: | - if [ ! -f "${{ steps.config.outputs.config_file }}" ]; then - echo "❌ Config file ${{ steps.config.outputs.config_file }} not found" - echo "Available config files:" - ls -la ./openapi/config*.yml || echo "No config files found" - exit 1 - fi - echo "✅ Using config file: ${{ steps.config.outputs.config_file }}" - - # Generate SDK - - name: Generate SDK - run: | - echo "🔧 Generating SDK for version: ${{ github.event.inputs.api_version }}" - echo "📄 Config: ${{ steps.config.outputs.config_file }}" - echo "🌐 Spec: ${{ steps.config.outputs.spec_url }}" - echo "📁 Output: ${{ steps.config.outputs.output_dir }}" - - openapi-generator-cli generate \ - -i ${{ steps.config.outputs.spec_url }} \ - -g typescript-axios \ - -c ${{ steps.config.outputs.config_file }} \ - -t ./openapi/templates \ - -o ${{ steps.config.outputs.output_dir }} - - # Test TypeScript compilation - - name: Test TypeScript compilation - run: | - cd ${{ steps.config.outputs.output_dir }} - npm install - npm run build - echo "✅ TypeScript compilation successful" - - # Archive generated code as artifact for inspection - - name: Archive generated code - uses: actions/upload-artifact@v3 - with: - name: generated-sdk-${{ github.event.inputs.api_version }} - path: ${{ steps.config.outputs.output_dir }} - retention-days: 7 - - # Validation summary - - name: Validation summary - run: | - echo "🎉 Generation successful for ${{ github.event.inputs.api_version }}!" - - # Show package.json name for verification - PACKAGE_NAME=$(cat ${{ steps.config.outputs.output_dir }}/package.json | grep '"name"' | cut -d'"' -f4) - PACKAGE_VERSION=$(cat ${{ steps.config.outputs.output_dir }}/package.json | grep '"version"' | cut -d'"' -f4) - echo "📦 Generated package: $PACKAGE_NAME@$PACKAGE_VERSION" - - # Count API files - API_COUNT=$(find ${{ steps.config.outputs.output_dir }} -name "*api.ts" | wc -l) - echo "🔍 Generated API files: $API_COUNT" - - # Show file structure - echo "" - echo "📂 Generated file structure:" - ls -lh ${{ steps.config.outputs.output_dir }} - - # Publish to GitHub Packages (Safe Testing) - - name: Publish to GitHub Packages - if: ${{ github.event.inputs.test_level == 'github_packages' }} - run: | - cd ${{ steps.config.outputs.output_dir }} - - # Configure for GitHub Packages - npm config set registry https://npm.pkg.github.com - npm config set //npm.pkg.github.com/:_authToken ${{ secrets.GITHUB_TOKEN }} - - # Publish the test package - npm publish - - PACKAGE_NAME=$(cat package.json | grep '"name"' | cut -d'"' -f4) - PACKAGE_VERSION=$(cat package.json | grep '"version"' | cut -d'"' -f4) - - echo "✅ Published test package to GitHub Packages" - echo "📦 Package: $PACKAGE_NAME@$PACKAGE_VERSION" - echo "🔗 View at: https://github.com/mxenabled/mx-platform-node/packages" - - - name: Slack notification - if: always() - uses: ravsamhq/notify-slack-action@v2 - with: - status: ${{ job.status }} - token: ${{ secrets.GITHUB_TOKEN }} - notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" - notify_when: "failure" - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/docs/Adding-a-New-API-Version.md b/docs/Adding-a-New-API-Version.md new file mode 100644 index 0000000..e61e7dc --- /dev/null +++ b/docs/Adding-a-New-API-Version.md @@ -0,0 +1,302 @@ +# Adding a New API Version to mx-platform-node + +**Document Purpose**: Step-by-step guide for adding support for a new API version (e.g., `v20300101`) to the mx-platform-node repository. + +**Last Updated**: January 27, 2026 +**Time to Complete**: 30-45 minutes +**Prerequisites**: Familiarity with the multi-version architecture (see [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md)) + +--- + +## Overview + +When the OpenAPI repository releases a new API version, adding it to mx-platform-node requires four main steps: +1. Create a configuration file for the new API version +2. Update workflow files to include the new version in the matrix +3. Coordinate with the OpenAPI repository on payload format +4. Verify the setup works correctly + +The process is designed to be self-contained and non-breaking—existing versions continue to work regardless of whether you've added new ones. + +--- + +## Step 1: Create Configuration File + +Create a new configuration file for your API version: `openapi/config-v20300101.yml` + +```yaml +--- +generatorName: typescript-axios +npmName: mx-platform-node +npmVersion: 4.0.0 # New major version for new API +apiVersion: v20300101 +supportsES6: true +.openapi-generator-ignore: true +``` + +**Critical: Semantic Versioning Rule** + +Major version must be unique and increment sequentially: +- v20111101 API → npm version 2.x.x +- v20250224 API → npm version 3.x.x +- v20300101 API → npm version 4.x.x (NEW) + +This ensures moving between major versions always indicates an API change. + +**File Locations and Naming** + +- **Config file**: `openapi/config-v.yml` +- **Generated directory**: `v/` (created automatically on first generation) +- **API version format**: Must match spec files in openapi repository (e.g., `v20300101.yml`) + +### Verify the Config File + +Test that your config file is valid YAML and contains all required fields: +```bash +ruby -e "require 'yaml'; puts YAML.load(File.read('openapi/config-v20300101.yml'))" +``` + +Should output valid parsed YAML without errors. + +--- + +## Step 2: Update Workflow Files + +### 2.1 Update on-push-master.yml + +Add the new version to the matrix strategy: + +**File**: `.github/workflows/on-push-master.yml` + +**Find this section**: +```yaml +strategy: + matrix: + version: + - api_version: v20111101 + npm_version: 2 + - api_version: v20250224 + npm_version: 3 +``` + +**Add new entry**: +```yaml +strategy: + matrix: + version: + - api_version: v20111101 + npm_version: 2 + - api_version: v20250224 + npm_version: 3 + - api_version: v20300101 # NEW + npm_version: 4 +``` + +### 2.2 Update Path Triggers + +In the same file, add the new path trigger: + +**Find this section**: +```yaml +on: + push: + branches: [master] + paths: + - 'v20111101/**' + - 'v20250224/**' +``` + +**Add new path**: +```yaml +on: + push: + branches: [master] + paths: + - 'v20111101/**' + - 'v20250224/**' + - 'v20300101/**' # NEW +``` + +This ensures that when changes to `v20300101/` are pushed to master, the publish and release workflows automatically trigger. + +### 2.3 Verify Workflow Syntax + +Check that your YAML is valid: +```bash +ruby -e "require 'yaml'; puts YAML.load(File.read('.github/workflows/on-push-master.yml'))" +``` + +--- + +## Step 3: Coordinate with OpenAPI Repository + +The OpenAPI repository must be updated to send the new API version in the `repository_dispatch` event payload. + +### What Needs to Change in openapi repo + +When openapi repository wants to trigger generation for the new version, it should send: + +```json +{ + "api_versions": "v20111101,v20250224,v20300101" +} +``` + +**Example curl command** (what openapi repo would use): +```bash +curl -X POST \ + https://api.github.com/repos/mxenabled/mx-platform-node/dispatches \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + -d '{ + "event_type": "generate_sdk", + "client_payload": { + "api_versions": "v20111101,v20250224,v20300101" + } + }' +``` + +### Backward Compatibility + +If the OpenAPI repository doesn't send the new version in the payload: +- `generate_publish_release.yml` defaults to `v20111101` only +- Existing versions continue to work unchanged +- New version won't generate until explicitly included in the payload + +This is intentional—allows phased rollout without breaking existing workflows. + +### Transition Plan + +**Phase 1**: New config exists but openapi repo doesn't send the version +- System works with v20111101 and v20250224 only +- New version `v20300101/` directory doesn't get created +- No errors or issues + +**Phase 2**: OpenAPI repo updated to send new version +- Next `generate_publish_release.yml` run includes all three versions +- `v20300101/` directory created automatically +- All three versions published to npm in parallel + +--- + +## Step 4: Verify the Setup + +### 4.1 Manual Generation Test + +Test that your new version can be generated manually before waiting for upstream changes. + +Run the `generate.yml` workflow manually: +1. Go to GitHub Actions → `generate.yml` +2. Click "Run workflow" +3. **api_version**: Select `v20300101` (should appear in dropdown) +4. **version_bump**: Select `skip` (for testing, no version bump) +5. Click "Run workflow" + +**Expected Results**: +- Workflow completes successfully +- A new PR is created with branch name: `openapi-generator-v20300101-4.0.0` +- PR contains generated SDK files in new `v20300101/` directory + +### 4.2 Verify Generated Structure + +Once PR is created (before merging), verify the generated files: + +```bash +# Check directory was created +ls -la v20300101/ + +# Verify package.json has correct version +cat v20300101/package.json | grep -A 2 '"version"' + +# Should show: +# "version": "4.0.0", +# "apiVersion": "v20300101", +``` + +### 4.3 Check npm Package Metadata + +The generated `package.json` should have: + +```json +{ + "name": "mx-platform-node", + "version": "4.0.0", + "description": "MX Platform Node.js SDK (v20300101 API)", + "apiVersion": "v20300101" +} +``` + +This ensures npm registry will show the correct API version in the package description. + +### 4.4 Verify on-push-master.yml Would Trigger + +Check that your path trigger configuration is correct: + +```bash +# This confirms the path syntax is valid +git status --porcelain | grep "v20300101/" +``` + +After merging the PR, pushing to master with changes in `v20300101/` should automatically trigger `on-push-master.yml`. + +--- + +## Checklist + +Use this checklist to verify you've completed all steps: + +- [ ] Created `openapi/config-v20300101.yml` with correct syntax +- [ ] Major version in config is unique and sequential (4.0.0 for v20300101) +- [ ] Updated `.github/workflows/on-push-master.yml` matrix with new version +- [ ] Updated `.github/workflows/on-push-master.yml` paths with `v20300101/**` +- [ ] Verified workflow YAML syntax is valid +- [ ] Coordinated with OpenAPI repository on payload changes +- [ ] Ran `generate.yml` manual test with new version +- [ ] Verified generated `package.json` has correct version and apiVersion +- [ ] Verified PR would be created with correct branch name format +- [ ] Merged test PR to master (or closed it if testing only) +- [ ] Confirmed no errors in existing version workflows + +--- + +## Troubleshooting + +### Config file not found during generation +**Cause**: Filename doesn't match API version +**Solution**: Verify config file is named exactly `openapi/config-v20300101.yml` + +### New version doesn't appear in generate.yml dropdown +**Cause**: Config file syntax error or not recognized +**Solution**: Verify YAML syntax with `ruby -e "require 'yaml'; puts YAML.load(File.read('openapi/config-v20300101.yml'))"` + +### Generated version is 2.x.x or 3.x.x instead of 4.0.0 +**Cause**: Wrong major version in config file +**Solution**: Update `npmVersion: 4.0.0` in config file to use unique major version + +### on-push-master.yml doesn't trigger after merge +**Cause**: Path trigger syntax incorrect +**Solution**: Verify path is exactly `v20300101/**` with forward slashes + +### Existing versions break after adding new version +**Cause**: Matrix syntax error or bad YAML +**Solution**: Verify on-push-master.yml YAML is valid; test existing workflows still work + +--- + +## Next Steps + +Once verified: + +1. **Commit changes**: Push config and workflow updates to a feature branch +2. **Create PR**: Get code review of workflow changes +3. **Merge PR**: Once approved, merge to master +4. **Wait for OpenAPI updates**: New version won't generate until OpenAPI repo sends it in payload +5. **Monitor first generation**: Watch the automatic `generate_publish_release.yml` run when OpenAPI repo triggers it + +--- + +## Reference + +For more details on how the workflows use these configurations, see: +- [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md) - Architecture overview +- [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md) - Detailed implementation diff --git a/docs/Multi-Version-SDK-Flow.md b/docs/Multi-Version-SDK-Flow.md new file mode 100644 index 0000000..5b9e319 --- /dev/null +++ b/docs/Multi-Version-SDK-Flow.md @@ -0,0 +1,241 @@ +# Multi-Version SDK Flow - Quick Reference + +**Document Purpose**: Quick-reference guide to the multi-version SDK generation, publishing, and release system. This is your entry point to understanding how the system works. + +**Last Updated**: January 27, 2026 +**Read Time**: 5-10 minutes +**Audience**: Anyone joining the team or needing a system overview + +--- + +## What Is This? + +The mx-platform-node repository publishes multiple API versions of the same npm package: +- `mx-platform-node@2.x.x` → API v20111101 +- `mx-platform-node@3.x.x` → API v20250224 + +Each version is independently generated, tested, published to npm, and released on GitHub. The system is **automatic** (triggered by OpenAPI spec changes) and **manual** (triggered by developer workflows). + +### Key Design Principles +1. **Separate Directories**: Each API version in its own directory (`v20111101/`, `v20250224/`) +2. **Reusable Workflows**: `workflow_call` passes version info to publish/release jobs +3. **One Config Per Version**: `config-v20111101.yml`, `config-v20250224.yml`, etc. +4. **Matrix Parallelization**: All versions generate/publish simultaneously +5. **Safety First**: Skip-publish flags and path-based triggers prevent accidents + +--- + +## Three Ways Things Happen + +### 🤖 Flow 1: Automatic (Upstream Triggers) +OpenAPI spec changes → `generate_publish_release.yml` runs → SDK generated, published, released + +**When**: OpenAPI repository sends `repository_dispatch` with API versions +**Who**: Automated, no human intervention +**Result**: All specified versions generated in parallel, committed, published, released in single workflow + +**Key Details**: See [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md#flow-1-automatic-multi-version-generation-repository-dispatch) + +### 👨‍💻 Flow 2: Manual (Developer Triggers) +Developer runs `generate.yml` → SDK generated → PR created → Developer merges → Auto-publish triggers + +**When**: Developer clicks "Run workflow" on `generate.yml` +**Who**: Developer (controls version selection and bump strategy) +**Inputs**: +- `api_version`: Choose `v20111101` or `v20250224` +- `version_bump`: Choose `skip`, `minor`, or `patch` + +**Result**: SDK generated in feature branch, PR created for review, auto-publishes on merge + +**Key Details**: See [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md#flow-2-manual-multi-version-generation-workflow-dispatch) + +### 🔄 Flow 3: Auto-Publish (Master Push) +Changes pushed to `v20111101/**` or `v20250224/**` → `on-push-master.yml` runs → Publishes and releases + +**When**: Any commit to master with version directory changes +**Who**: Triggered automatically, can be skipped with `[skip-publish]` flag +**Safety**: Only affected version(s) published (no cross-version interference) + +**Key Details**: See [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md#flow-3-auto-publish-trigger-with-path-based-matrix-execution-on-push-masteryml) + +--- + +## Visual Flows + +### Automatic Flow + +```mermaid +sequenceDiagram + participant OpenAPI as OpenAPI
Repository + participant GH as GitHub
Actions + participant Gen as generate_publish
_release.yml + participant npm as npm
Registry + participant GHRel as GitHub
Releases + + OpenAPI->>GH: Changes to v20111101.yml
and v20250224.yml
(repository_dispatch) + GH->>+Gen: Trigger workflow + Gen->>Gen: Matrix: Generate both versions
in parallel + Gen->>Gen: Commit to master
Update CHANGELOG.md + deactivate Gen + + rect rgba(0, 255, 0, .1) + note right of Gen: Parallel Publishing + par publish v20111101 + npm->>npm: npm publish v2.0.1 + and publish v20250224 + npm->>npm: npm publish v3.0.1 + and release v20111101 + GHRel->>GHRel: Create tag v2.0.1 + and release v20250224 + GHRel->>GHRel: Create tag v3.0.1 + end + end +``` + +### Manual Flow + +```mermaid +sequenceDiagram + participant Dev as Developer + participant GH as GitHub
Actions + participant Gen as generate.yml + participant Review as Code
Review + participant Auto as on-push-
master.yml + participant npm as npm + participant GHRel as GitHub + + Dev->>GH: Run generate.yml
(select API + bump) + GH->>+Gen: Trigger workflow + Gen->>Gen: Generate SDK
Create PR + deactivate Gen + + Review->>Review: Review & Approve + Review->>Review: Merge PR to master + + GH->>+Auto: on-push-master.yml + Auto->>npm: Publish selected version + Auto->>GHRel: Create release + deactivate Auto +``` + +### Auto-Publish Flow + +```mermaid +sequenceDiagram + participant Push as Git Push + participant Auto as on-push-
master.yml + participant pub as publish.yml + participant rel as release.yml + participant npm as npm + participant GHRel as GitHub + + Push->>+Auto: Push to master
(v20111101/** changed) + Auto->>pub: Matrix: Publish v20111101 + pub->>npm: npm publish + Auto->>rel: Matrix: Release v20111101 + rel->>GHRel: Create tag + deactivate Auto +``` + +--- + +## Common Tasks + +### I Want to Add a New API Version +→ See [Adding-a-New-API-Version.md](Adding-a-New-API-Version.md) + +**Quick summary**: Create config file → Update workflow matrix → Coordinate with OpenAPI repo + +### Something Broke +→ See [Troubleshooting-Guide.md](Troubleshooting-Guide.md) + +**Quick summary**: Check error message → Find section → Follow solution + +### I Need Deep Technical Details +→ See [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md) + +**Covers**: Step-by-step implementation, configuration files, scripts, environment variables + +--- + +## Key Files Reference + +| File | Purpose | Used By | +|------|---------|---------| +| `.github/workflows/generate_publish_release.yml` | Automatic generation from upstream API changes | OpenAPI repo | +| `.github/workflows/generate.yml` | Manual generation with version selection | Developer | +| `.github/workflows/on-push-master.yml` | Auto-publish trigger with path-based matrix | Any master push | +| `.github/workflows/publish.yml` | Publishes SDK to npm | publish_release & on-push-master | +| `.github/workflows/release.yml` | Creates GitHub release | publish_release & on-push-master | +| `.github/version.rb` | Bumps version in config files | Workflows | +| `.github/clean.rb` | Removes old generated files | Workflows | +| `openapi/config-v20111101.yml` | Config for v20111101 generation | generate_publish_release & generate | +| `openapi/config-v20250224.yml` | Config for v20250224 generation | generate_publish_release & generate | +| `openapi/templates/package.mustache` | npm package.json template | OpenAPI Generator | +| `openapi/templates/README.mustache` | README.md template | OpenAPI Generator | + +--- + +## Semantic Versioning + +**Major version = API version** (no exceptions) + +| npm Version | API Version | What It Means | +|------------|------------|--------------| +| 2.x.x | v20111101 | First stable API | +| 3.x.x | v20250224 | Second API version | +| 4.x.x | (future) | Next API version | + +Consumers know exactly which API they have by checking the major version number. + +--- + +## Backward Compatibility + +If OpenAPI repo doesn't send new version in payload, the system doesn't break: +- Existing versions continue to work unchanged +- New version doesn't generate until explicitly requested +- No errors or warnings +- Phased rollout friendly + +--- + +## Safety Features + +| Feature | What It Does | When It Helps | +|---------|-------------|--------------| +| **Path-based triggers** | Only publish if `v20111101/**` or `v20250224/**` changed | Prevents false publishes from doc-only changes | +| **[skip-publish] flag** | Skip publish/release for this commit | During directory migrations or refactors | +| **Matrix conditionals** | Each version publishes only if its path changed | Prevents unintended version bumps | +| **Version validation** | Major version must match API version | Prevents semantic versioning violations | +| **Config file validation** | Workflow fails if config doesn't exist | Catches typos early | + +--- + +## Environment Variables & Secrets + +| Secret | Used For | +|--------|----------| +| `NPM_AUTH_TOKEN` | Publishing to npm registry | +| `GITHUB_TOKEN` | Creating releases (auto-provided) | +| `SLACK_WEBHOOK_URL` | Failure notifications | + +--- + +## Next Steps + +1. **Understand the architecture**: Read this document +2. **Need to add a version?**: Go to [Adding-a-New-API-Version.md](Adding-a-New-API-Version.md) +3. **Need to fix something?**: Go to [Troubleshooting-Guide.md](Troubleshooting-Guide.md) +4. **Need implementation details?**: Go to [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md) + +--- + +## Document Overview + +| Document | Purpose | Read Time | +|----------|---------|-----------| +| **Multi-Version-SDK-Flow.md** | Overview & entry point (you are here) | 5-10 min | +| **Adding-a-New-API-Version.md** | Step-by-step guide for new versions | 10-15 min | +| **Troubleshooting-Guide.md** | Common issues & solutions | 5-10 min | +| **Workflow-and-Configuration-Reference.md** | Deep technical details | 20-30 min | diff --git a/docs/SDK-Generation-Publishing-Flow.md b/docs/SDK-Generation-Publishing-Flow.md index 03a47ae..a932625 100644 --- a/docs/SDK-Generation-Publishing-Flow.md +++ b/docs/SDK-Generation-Publishing-Flow.md @@ -1,10 +1,19 @@ -# SDK Generation, Publishing, and Release Flow +# SDK Generation, Publishing, and Release Flow (LEGACY - Single-Version) -**Document Purpose**: This document explains how the Node.js SDK is automatically generated, published to npm, and released. It covers both automatic triggers (from the OpenAPI repository) and manual generation flows (for development and testing). This is a reference guide for developers new to this repository. +> ⚠️ **ARCHIVED DOCUMENTATION** - This document describes the **single-version SDK system** that was in use before multi-version support was added. +> +> **For current documentation**, see: +> - [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md) - Current system overview +> - [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md) - Current technical details +> +> This document is kept for **historical reference** and may be useful for repositories that have not yet migrated to multi-version support. -**Last Updated**: January 20, 2026 +**Document Purpose**: This document explains how the Node.js SDK was automatically generated, published to npm, and released in the single-version system. It covers both automatic triggers (from the OpenAPI repository) and manual generation flows (for development and testing). + +**Last Updated**: January 20, 2026 (ARCHIVED) **Repository**: mx-platform-node -**Author**: DevExperience Team +**Author**: DevExperience Team +**Status**: Legacy - Superseded by multi-version flows --- diff --git a/docs/Troubleshooting-Guide.md b/docs/Troubleshooting-Guide.md new file mode 100644 index 0000000..030fe37 --- /dev/null +++ b/docs/Troubleshooting-Guide.md @@ -0,0 +1,384 @@ +# Troubleshooting Guide + +**Document Purpose**: Quick reference for diagnosing and fixing issues in the multi-version SDK generation, publishing, and release workflows. + +**Last Updated**: January 27, 2026 +**Audience**: Developers debugging workflow failures + +--- + +## Quick Diagnosis + +### No SDK Generated +Check in this order: +1. Is the OpenAPI spec file accessible? +2. Does the config file exist for that API version? +3. Are there syntax errors in the config file? + +### SDK Generated But Not Published +Check in this order: +1. Did the commit reach master successfully? +2. Is `NPM_AUTH_TOKEN` secret valid? +3. Did the path filter (`v20111101/**`, etc.) match the changes? + +### SDK Generated and Published But Release Not Created +Check in this order: +1. Did publish step complete successfully? +2. Does the release tag already exist? +3. Does `GITHUB_TOKEN` have release creation permissions? + +--- + +## Common Issues and Solutions + +### Generate Workflow: Config File Not Found + +**Error Message**: +``` +Error: Config file not found: openapi/config-v20111101.yml +``` + +**Causes**: +- Config file doesn't exist for selected API version +- Filename typo or wrong path +- API version not yet configured + +**Solutions**: +1. Verify file exists: `ls -la openapi/config-v*.yml` +2. Check filename matches API version exactly +3. For new API versions, create config file first (see [Adding-a-New-API-Version.md](Adding-a-New-API-Version.md)) + +--- + +### Generate Workflow: Semantic Versioning Validation Fails + +**Error Message**: +``` +Error: Invalid npm version for API v20250224 +Expected: 3.x.x +Got: 2.0.0 +``` + +**Cause**: Major version in config doesn't match API version + +**Semantic Versioning Rule**: +- v20111101 API must use `npmVersion: 2.x.x` +- v20250224 API must use `npmVersion: 3.x.x` +- New APIs must use next sequential major version + +**Solution**: Update config file with correct major version +```yaml +--- +npmName: mx-platform-node +npmVersion: 3.0.0 # Must start with 3 for v20250224 +apiVersion: v20250224 +``` + +--- + +### Generate Workflow: Config File Syntax Error + +**Error Message**: +``` +YAML syntax error in openapi/config-v20111101.yml +``` + +**Common Issues**: +- Incorrect indentation (YAML is whitespace-sensitive) +- Missing quotes around values with special characters +- Trailing spaces after values +- Invalid field names + +**How to Test**: +```bash +ruby -e "require 'yaml'; puts YAML.load(File.read('openapi/config-v20111101.yml'))" +``` + +If this errors, your YAML syntax is wrong. + +**Solution**: Fix YAML syntax and re-test +```yaml +--- +generatorName: typescript-axios # Must start with --- +npmName: mx-platform-node +npmVersion: 2.0.0 +apiVersion: v20111101 +supportsES6: true +.openapi-generator-ignore: true +``` + +--- + +### Publish Fails: NPM Auth Token Invalid + +**Error Message**: +``` +npm ERR! 401 Unauthorized +npm ERR! need auth 401 Unauthorized - PUT https://registry.npmjs.org/mx-platform-node +``` + +**Causes**: +- `NPM_AUTH_TOKEN` secret expired or revoked +- Token doesn't have publish permissions for `mx-platform-node` +- Token was deleted from GitHub repository secrets +- Wrong npm registry configured + +**Solutions**: +1. Verify token exists: Go to GitHub repo → Settings → Secrets and variables → Actions → Look for `NPM_AUTH_TOKEN` +2. If missing or expired, generate new token: + - Log into npm.js as maintainer + - Create new "Publish" scope token (not Read-only) + - Copy full token value + - Update secret in GitHub repository +3. Verify token has permissions for `mx-platform-node` package +4. Wait 5 minutes after updating secret before retrying + +--- + +### Publish Fails: Version Already Published + +**Error Message**: +``` +npm ERR! 403 Forbidden - PUT https://registry.npmjs.org/mx-platform-node/2.0.5 +You cannot publish over the previously published version 2.0.5 +``` + +**Cause**: Version already exists on npm registry + +**Why This Happens**: +- SDK was already published with this version number +- Version bump didn't increment (check `version.rb` output) +- Wrong version directory being published + +**Solutions**: +1. If intentional, increment version and regenerate: + ```bash + ruby .github/version.rb patch openapi/config-v20111101.yml + ``` +2. If accidental duplicate: + - Check `openapi/config-v20111101.yml` has next sequential version + - Run generate workflow again to create PR with new version + - Merge PR to trigger publish with correct version + +--- + +### Release Not Created After Publish + +**Error Message**: +``` +gh release create: error: failed to create release +fatal: A release with this tag already exists +``` + +**Causes**: +- Release tag already exists (e.g., `v2.0.1`) +- `GITHUB_TOKEN` lacks release creation permissions +- Typo in tag name + +**Solutions**: +1. Check if release already exists: + ```bash + git tag -l | grep v2.0.1 + ``` +2. If release exists but workflow failed, delete it: + - Go to GitHub repo → Releases → Find the release + - Click "Delete" on the release + - Re-run the release workflow +3. Verify `GITHUB_TOKEN` has release creation permissions (usually auto-provided by GitHub) +4. Check that version in `package.json` matches tag format (`v2.0.1`, not `2.0.1`) + +--- + +### Both Versions Publish When Only One Should + +**Scenario**: Merged a PR for v20111101 only, but both v20111101 and v20250224 published + +**Causes**: +- Changes were made to both `v20111101/` and `v20250224/` directories +- Unintended changes to both directories were committed +- Path filter in `on-push-master.yml` has wrong syntax + +**Solutions**: +1. Review what changed in the merged PR: + ```bash + git log --oneline -n 5 | head -1 + git show --name-status | grep -E "v20111101|v20250224" + ``` +2. If only one version should have changed: + - Revert the commit + - Fix the unintended changes + - Create a new PR with only the intended changes +3. If both versions should have changed: + - This is correct behavior (both path filters matched) + - Both versions published as expected + +--- + +### Generation Produces Stale Spec Files + +**Symptom**: Generated SDK doesn't include changes that were in the OpenAPI spec + +**Cause**: GitHub's raw.githubusercontent.com CDN cached the old file for 5 minutes + +**Why This Happens**: +- OpenAPI repo commits spec change at 2:00 PM +- Repository dispatch sent immediately at 2:01 PM +- Workflow runs at 2:02 PM but CDN still has 2:00 PM version +- SDK generated from stale spec + +**Solution**: Already implemented in `generate_publish_release.yml` +- Uses commit SHA in spec URL: `raw.githubusercontent.com/mxenabled/openapi//openapi/v20111101.yml` +- Commit SHA bypasses CDN and guarantees exact spec version +- Nothing to do—this is automatic + +**Manual Generation Note**: `generate.yml` uses `master` branch reference (not commit SHA) because developer controls timing and doesn't have CDN race condition concern. + +--- + +### Workflow Not Triggering on Push + +**Symptom**: Merged a PR with changes to `v20111101/` directory, but `on-push-master.yml` didn't run + +**Causes**: +- Path filter in `on-push-master.yml` has syntax error or wrong path +- Changes were not actually in the version directory +- Commit was made to wrong branch +- Workflow file has syntax error + +**Solutions**: +1. Verify path filter syntax is correct: + ```yaml + on: + push: + branches: [master] + paths: + - 'v20111101/**' # Correct format + - 'v20250224/**' + ``` +2. Check what files were actually changed: + ```bash + git diff HEAD~1..HEAD --name-only | grep -E "v20111101|v20250224" + ``` +3. Verify commit was to `master` branch: + ```bash + git log --oneline -n 1 + git branch -r --contains HEAD + ``` +4. Check `on-push-master.yml` syntax: + ```bash + ruby -e "require 'yaml'; puts YAML.load(File.read('.github/workflows/on-push-master.yml'))" + ``` + +--- + +### Skip-Publish Flag Not Working + +**Symptom**: Added `[skip-publish]` to commit message but workflow still published + +**Causes**: +- Flag syntax wrong (case-sensitive, needs brackets) +- Flag in PR title/body instead of commit message +- Commit message doesn't include the flag + +**Solution**: Commit message must include exact text `[skip-publish]` +```bash +# Correct +git commit -m "Migrate SDK structure [skip-publish]" + +# Wrong - will not work +git commit -m "Migrate SDK structure [SKIP-PUBLISH]" +git commit -m "Migrate SDK structure (skip-publish)" +git commit -m "Migrate SDK structure skip-publish" +``` + +--- + +### Version.rb Script Errors + +#### Error: "Version directory parameter required" +``` +Error: Version directory parameter required. Usage: ruby clean.rb +``` + +**Cause**: `clean.rb` called without version directory argument + +**Solution**: Always provide version directory +```bash +ruby .github/clean.rb v20111101 # Correct +ruby .github/clean.rb # Wrong - missing parameter +``` + +#### Error: "Invalid version bump type" +``` +Error: Invalid version bump type: major. Supported: 'minor' or 'patch' +``` + +**Cause**: Tried to use `major` option (not allowed for semantic versioning) + +**Solution**: Use only `minor` or `patch` +```bash +ruby .github/version.rb patch openapi/config-v20111101.yml # Correct +ruby .github/version.rb major openapi/config-v20111101.yml # Wrong - major not allowed +``` + +#### Error: "Config file not found" +``` +Error: Config file not found: openapi/config-invalid.yml +``` + +**Cause**: Config file path doesn't exist + +**Solution**: Verify file path and spelling +```bash +ls -la openapi/config-v*.yml # List valid files +ruby .github/version.rb patch openapi/config-v20111101.yml # Use correct path +``` + +--- + +### GitHub Actions Workflow Syntax Errors + +**Error Message** (in GitHub Actions UI): +``` +Invalid workflow file +``` + +**Common Causes**: +- YAML indentation error +- Invalid GitHub Actions syntax +- Missing required fields +- Circular job dependencies + +**How to Debug**: +1. Go to GitHub repo → Actions → Select failed workflow +2. Click on the workflow run +3. Look for error message at top (usually shows line number) +4. Check YAML syntax locally: + ```bash + ruby -e "require 'yaml'; YAML.load_file('.github/workflows/on-push-master.yml')" + ``` + +**Most Common Fix**: Indentation +- GitHub Actions workflows are YAML files +- Indentation must be consistent (usually 2 spaces) +- Use an editor with YAML validation + +--- + +## Getting Help + +If you encounter an issue not covered above: + +1. **Check workflow logs**: Go to GitHub repo → Actions → Failed workflow → Click run → Expand failed step +2. **Review error message**: Look for specific file names, line numbers, or error codes +3. **Check recent changes**: Did a recent PR change workflows or configs? +4. **Test locally**: Try running Ruby scripts manually to verify syntax +5. **Ask the team**: Reference the error message and steps to reproduce + +--- + +## Reference + +- [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md) - Architecture overview +- [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md) - Detailed implementation +- [Adding-a-New-API-Version.md](Adding-a-New-API-Version.md) - Step-by-step guide for new versions diff --git a/docs/Workflow-and-Configuration-Reference.md b/docs/Workflow-and-Configuration-Reference.md new file mode 100644 index 0000000..a2827e4 --- /dev/null +++ b/docs/Workflow-and-Configuration-Reference.md @@ -0,0 +1,581 @@ +# Workflow and Configuration Reference + +**Document Purpose**: Detailed technical reference for the multi-version SDK generation, publishing, and release workflows. Covers implementation details, configuration files, and system architecture. + +**Last Updated**: January 27, 2026 +**Audience**: Developers who need to understand or modify the implementation + +--- + +## Flow 1: Automatic Multi-Version Generation (Repository Dispatch) + +### Trigger +OpenAPI specifications change in the upstream `openapi` repository → Repository sends `repository_dispatch` event with optional `api_versions` payload → `generate_publish_release.yml` workflow is triggered + +### Backward Compatibility Model +- **No Payload (v20111101 only)**: If openapi repo sends `repository_dispatch` without `api_versions` field, defaults to generating v20111101 only +- **Single Version Payload** (`api_versions: "v20111101"`): Generates only the specified version +- **Multi-Version Payload** (`api_versions: "v20111101,v20250224"`): Generates both versions in parallel + +This allows phased migration: current behavior works as-is, and when the openapi repo is ready for multi-version, no code changes are needed in mx-platform-node. + +### Implementation + +**Workflow**: `.github/workflows/generate_publish_release.yml` + +#### Step 1: Setup - Determine Versions to Generate + +```yaml +env: + VERSIONS_TO_GENERATE: ${{ github.event.client_payload.api_versions || 'v20111101' }} +``` + +- If `api_versions` in payload: Use specified versions (e.g., `v20111101,v20250224`) +- If no payload: Default to `v20111101` (backward-compatible single-version behavior) + +#### Step 2: Generate SDKs (Matrix Execution) + +**Matrix Strategy**: Each API version runs as independent matrix job in parallel + +```yaml +strategy: + matrix: + api_version: [v20111101, v20250224] +``` + +**For Each Version** (e.g., v20111101): + +1. **Clean Version Directory** + - Command: `ruby .github/clean.rb v20111101` + - Deletes previously generated SDK files from that version directory only + - Prevents accidentally deleting unrelated version code + +2. **Setup Workflow Files** + - Copy `.openapi-generator-ignore` to version directory + - Create directory structure for generation + +3. **Bump Version** + - Script: `ruby .github/version.rb patch openapi/config-v20111101.yml` + - Reads `npmVersion` from config, increments, writes back + - Example: 2.0.0 → 2.0.1 (patch) or 2.1.0 (minor) + +4. **Generate SDK from OpenAPI Spec** + - **Input Spec URL**: Version-specific with commit SHA to bypass CDN cache + ``` + https://raw.githubusercontent.com/mxenabled/openapi//openapi/v20111101.yml + ``` + - **Why Commit SHA**: GitHub's raw CDN caches files for 5 minutes. Without the commit SHA, a workflow triggered immediately after a spec change might pull a cached (stale) version instead of the new one. The commit SHA ensures we always use the exact spec that triggered the workflow. + - **Output Directory**: `v20111101/` (version-specific) + - **Configuration**: Uses version-specific config file with correct `npmVersion` and `apiVersion` + - **Templates**: Shared templates in `./openapi/templates/` use `{{apiVersion}}` and `{{npmVersion}}` placeholders + - **Process**: + 1. Install OpenAPI Generator CLI globally + 2. Run TypeScript-Axios generator with version-specific config + 3. Generates SDK code in version directory + +5. **Copy Documentation** + - Copy documentation files to version directory: + - `LICENSE` → `v20111101/LICENSE` + - `MIGRATION.md` → `v20111101/MIGRATION.md` + - `.openapi-generator-ignore` → `v20111101/.openapi-generator-ignore` + +6. **Upload Artifacts** + - Upload generated SDK to workflow artifact storage + - Allows atomic multi-version commit after all matrix jobs complete + +#### Step 3: Post-Generation Processing (After All Matrix Jobs Complete) + +1. **Download Artifacts** + - Retrieve generated SDKs for all versions from artifact storage + +2. **Track Generated Versions** + - Record which directories were actually generated + - Used by CHANGELOG automation to add entries only for generated versions + +3. **Update CHANGELOG.md** + - Find first version entry: `grep -n "^##" CHANGELOG.md` + - Insert new entries after document header, before first existing entry + - Format: `## [X.Y.Z] - YYYY-MM-DD (API vXXXXXXXX)` + - Only add entries for versions that were actually generated + - Example: + ```markdown + # Changelog + + ## [2.0.1] - 2026-01-27 (v20111101 API) + Updated v20111101 API specification. + + ## [3.0.1] - 2026-01-27 (v20250224 API) + Updated v20250224 API specification. + ``` + +4. **Copy CHANGELOG to Version Directories** + - Copy root `CHANGELOG.md` to each version directory + - Each npm package includes changelog for users + +#### Step 4: Commit All Changes to Master + +- **Git Config**: Uses `devexperience` bot account +- **Commit Message**: `"Generated Node.js SDKs [v20111101=2.0.1,v20250224=3.0.1]"` +- **Files Committed**: Updated config files, generated SDK directories, updated CHANGELOG.md +- **Target Branch**: Directly commits to `master` (no PR created for automatic flow) +- **Atomic Operation**: All versions committed together in single commit + +#### Step 5: Publish to npm (Parallel Matrix Execution) + +**Architecture**: Uses `workflow_call` to invoke `publish.yml` as reusable workflow + +**Why workflow_call?** Repository dispatch events don't support input parameters. `workflow_call` allows passing `version_directory` to specify which version directory contains the SDK to publish. + +**Process**: +1. Call `publish.yml` with version-specific directory +2. Navigate to version directory (e.g., `v20111101/`) +3. Install dependencies: `npm install` +4. Publish to npm: `npm publish` (no tag for production) +5. Use `NPM_AUTH_TOKEN` secret for authentication + +**Result**: +- `mx-platform-node@2.0.1` published to npm (v20111101 API) +- `mx-platform-node@3.0.1` published to npm (v20250224 API) +- Both major versions coexist on npm registry under same package name + +#### Step 6: Create GitHub Releases (Parallel Matrix Execution) + +**Same architecture as publish**: Uses `workflow_call` to invoke `release.yml` + +**Process**: +1. Read version from version-specific `package.json` +2. Create GitHub release with version-specific tag (e.g., `v2.0.1`, `v3.0.1`) +3. Release body includes API version and links to API documentation + +**Result**: +- GitHub release `v2.0.1` created (v20111101 API) +- GitHub release `v3.0.1` created (v20250224 API) +- Both versions have separate release history + +--- + +## Flow 2: Manual Multi-Version Generation (Workflow Dispatch) + +### Trigger +Developer manually clicks "Run workflow" on `generate.yml` in GitHub Actions UI + +### User Inputs + +1. **api_version** (required): Which API version to generate + - Options: `v20111101` or `v20250224` + - Maps to correct config file automatically + +2. **version_bump** (required): Version bump strategy + - Options: `skip`, `minor`, or `patch` (no major option) + - Major version locked to API version (semantic versioning) + - `skip`: Generate without bumping version (test/review mode) + +### Implementation + +**Workflow**: `.github/workflows/generate.yml` + +#### Step 1: Validate Inputs + +- **Config File Exists**: Verify selected API version config file exists +- **Semantic Versioning Check**: Verify major version matches API version +- **Fail Fast**: If validation fails, workflow stops before any generation + +#### Step 2: Version Bumping (Conditional) + +**Only runs if `version_bump` != `skip`** + +- Script: `ruby .github/version.rb openapi/config-v20111101.yml` +- Reads current version from config file +- Increments minor or patch based on input +- Writes updated version back to config file +- Output new version for next steps + +#### Step 3: Clean Version Directory + +- Script: `ruby .github/clean.rb v20111101` +- Deletes generated files from previous generation in that directory only +- Unrelated version directories untouched + +#### Step 4: Generate SDK + +- **Input Spec URL**: Master branch reference (not commit SHA) + - `https://raw.githubusercontent.com/mxenabled/openapi/master/openapi/v20111101.yml` + - Manual workflow doesn't have CDN cache concern since developer controls timing +- **Output Directory**: Version-specific (e.g., `v20111101/`) +- **Configuration**: Version-specific config file +- **Process**: + 1. Install OpenAPI Generator CLI + 2. Run TypeScript-Axios generator with selected config + 3. Copy documentation files to version directory + +#### Step 5: Update CHANGELOG.md + +- Insert new entry after document header, before first existing entry +- Format: `## [X.Y.Z] - YYYY-MM-DD (API vXXXXXXXX)` +- Only selected version's CHANGELOG entry added + +#### Step 6: Create Feature Branch + +- **Branch Name**: `openapi-generator-v20111101-2.0.1` +- Format: `openapi-generator--` +- Makes it easy to identify which API version each PR targets + +#### Step 7: Create Pull Request + +- **Command**: `gh pr create -f` +- **Destination**: Targets `master` branch +- **Status**: Awaits code review and approval before merging +- **Benefits**: Allows time to validate SDK quality and close/retry if needed + +#### Step 8: Trigger Publishing (After PR Merge) + +**Trigger**: When PR is merged to `master`, `on-push-master.yml` automatically activates (see Flow 3) + +**Workflows Called**: +1. `publish.yml` (via workflow_call with version_directory input) +2. `release.yml` (via workflow_call with version_directory input) + +**Result**: Same publishing and releasing as automatic flow + +--- + +## Flow 3: Auto-Publish Trigger with Path-Based Matrix Execution (on-push-master.yml) + +### Trigger +Push to `master` branch with changes in version-specific directories (`v20111101/**` or `v20250224/**`) + +### Skip-Publish Safety Mechanism +Include `[skip-publish]` in commit message to prevent publish/release for this push. + +**Use Case**: When making structural changes (e.g., directory migrations), commit with `[skip-publish]` flag to prevent accidental publishes. + +### Implementation + +**Workflow**: `.github/workflows/on-push-master.yml` + +**Architectural Approach**: Matrix strategy with conditional execution per iteration eliminates code duplication while maintaining clear, independent version management. + +#### Step 1: Check Skip-Publish Flag + +**Job**: `check-skip-publish` + +```yaml +- name: Check for skip-publish flag + run: | + if [[ "${{ github.event.head_commit.message }}" == *"[skip-publish]"* ]]; then + echo "skip_publish=true" >> $GITHUB_OUTPUT + else + echo "skip_publish=false" >> $GITHUB_OUTPUT + fi +``` + +- Parses HEAD commit message +- Sets output: `skip_publish` = true/false +- Used by subsequent jobs to determine execution + +#### Step 2: Matrix-Based Publish Jobs + +**Matrix Definition**: +```yaml +strategy: + matrix: + version: + - api_version: v20111101 + npm_version: 2 + - api_version: v20250224 + npm_version: 3 +``` + +**For Each Version**: + +**Job Executes When**: +- No upstream failures (`!cancelled()`) +- No `[skip-publish]` flag in commit message +- Files in this version's directory were changed + +**Process**: +1. Call `publish.yml` with version-specific directory +2. Navigate to version directory +3. Install dependencies and publish to npm +4. Each version publishes independently with its own version number + +**Result**: Each version publishes independently, no race conditions, parallel execution when both versions changed + +#### Step 3: Matrix-Based Release Jobs + +**Same Matrix Strategy as Publish** + +**For Each Version**: + +**Job Executes When**: +- Same conditions as publish (skip-publish flag, path match) +- **Plus**: Only after its corresponding publish job succeeds + +This ensures each version's release depends only on its own publish job, preventing race conditions. + +**Process**: +1. Call `release.yml` with version-specific directory +2. Read version from that directory's `package.json` +3. Create GitHub release with version-specific tag + +**Result**: Each version released independently, ordered after its corresponding publish job + +--- + +## Supporting Scripts + +### version.rb - Multi-Version Support + +**File**: `.github/version.rb` + +**Purpose**: Increment version numbers in configuration files + +**Usage**: `ruby .github/version.rb [config_file]` + +**Supported Options**: +- `minor`: Increment minor version (e.g., 2.0.0 → 2.1.0) +- `patch`: Increment patch version (e.g., 2.0.0 → 2.0.1) +- No `major` option (major version locked to API version) + +**Important**: npmVersion as Source of Truth + +The `npmVersion` field in the config file is the **authoritative source of truth** for the package version: + +1. **Config File** (Source of Truth) + - Contains persistent version number + - Lives in Git, checked in with each update + - Example: `openapi/config-v20111101.yml` contains `npmVersion: 2.0.0` + +2. **version.rb Script** (Updates Source of Truth) + - Reads current `npmVersion` from config file + - Receives bump instruction: "patch" or "minor" + - Calculates new version: 2.0.0 → 2.0.1 (patch) or 2.1.0 (minor) + - **Writes updated npmVersion back to config file** (persists to Git) + - Outputs new version to stdout (for workflow logging) + +3. **package.mustache Template** (Uses Source of Truth) + - Contains placeholder: `"version": "{{npmVersion}}"` + - OpenAPI Generator replaces `{{npmVersion}}` with value from config file + - Generates `package.json` with correct version number + +4. **Result** + - Generated `package.json` always has correct version + - Version comes entirely from config file + - No hardcoding in workflows or templates + +### clean.rb - Version-Targeted Deletion + +**File**: `.github/clean.rb` + +**Purpose**: Remove generated SDK files before regeneration for a specific version + +**Usage**: `ruby .github/clean.rb ` + +**Behavior**: +- Version-targeted deletion: deletes only specified version directory +- Protected files: `.git`, `.github`, `openapi`, other version directories, LICENSE, README, CHANGELOG +- Required parameter: must provide version directory name +- Error if parameter missing: raises clear error message + +--- + +## Configuration Files + +### openapi/config-v20111101.yml + +```yaml +--- +generatorName: typescript-axios +npmName: mx-platform-node +npmVersion: 2.0.0 +apiVersion: v20111101 +supportsES6: true +.openapi-generator-ignore: true +``` + +**Purpose**: Generates v20111101 API SDK as `mx-platform-node@2.x.x` + +**Key Fields**: +- `npmVersion`: Source of truth for package version (updated by `version.rb`) +- `apiVersion`: Passed to `package.mustache` for description and metadata +- `npmName`: Same across all configs (single package name with multiple major versions) +- `generatorName`: Language/framework for code generation (TypeScript-Axios) +- `supportsES6`: Target JavaScript version for transpilation +- `.openapi-generator-ignore`: Prevents overwriting certain files + +### openapi/config-v20250224.yml + +```yaml +--- +generatorName: typescript-axios +npmName: mx-platform-node +npmVersion: 3.0.0 +apiVersion: v20250224 +supportsES6: true +.openapi-generator-ignore: true +``` + +**Purpose**: Generates v20250224 API SDK as `mx-platform-node@3.x.x` + +### openapi/templates/package.mustache + +```json +{ + "name": "{{npmName}}", + "version": "{{npmVersion}}", + "description": "MX Platform Node.js SDK ({{apiVersion}} API)", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "apiVersion": "{{apiVersion}}", + "files": [ + "dist/", + "*.md" + ], + "scripts": { + "build": "tsc --declaration", + "test": "npm run build" + }, + "dependencies": { + "axios": "^1.6.2" + } +} +``` + +**Key Features**: +- `"version"`: Uses `{{npmVersion}}` from config (source of truth) +- `"description"`: Includes `{{apiVersion}}` to identify which API version (visible in npm registry) +- `"apiVersion"`: Custom field for programmatic access to API version +- `"files"`: Explicitly controls what gets published (critical for multi-version from subdirectories) + +**Consumer Discovery**: +- **In npm registry**: Description shows "MX Platform SDK (v20111101 API)" or "(v20250224 API)" +- **Programmatically**: + ```javascript + const pkg = require('mx-platform-node/package.json'); + console.log(pkg.apiVersion); // "v20111101" or "v20250224" + ``` + +### openapi/templates/README.mustache + +**Key Features**: +- Title includes `{{apiVersion}}`: `# MX Platform Node.js ({{apiVersion}} API)` +- SDK and API version clearly identified +- Version selection section explains available versions +- Links to correct API documentation per version + +--- + +## Path-Based Triggers + +### on-push-master.yml Path Configuration + +```yaml +on: + push: + branches: [master] + paths: + - 'v20111101/**' # Triggers publish/release for v20111101 + - 'v20250224/**' # Triggers publish/release for v20250224 + # Does NOT trigger on: + # - '.github/**' (workflow changes) + # - 'openapi/**' (config changes alone) + # - 'docs/**' (documentation changes) + # - 'README.md' (root documentation) +``` + +**Benefits**: +- Enhancement PRs (docs only) don't trigger publish +- Workflow file changes don't trigger publish +- Only actual SDK code changes trigger publish/release +- Each version independently triggers when its directory changes +- Prevents false publishes from non-SDK changes + +--- + +## Semantic Versioning Strategy + +The repository uses **semantic versioning with major version = API version**: + +| Version | API Version | Release Type | Notes | +|---------|------------|--------------|-------| +| 2.x.x | v20111101 | Stable | New minor/patch releases for spec updates | +| 3.x.x | v20250224 | Stable | New major version for new API version | +| 4.x.x | (future) | Future | When new API version available | + +**Key Principle**: Major version number directly tied to API version number. +- Moving between major versions (2.x → 3.x) always means API change +- No confusion about which API version is in use +- Consumers can use `package.json` to determine API version + +--- + +## Environment Variables & Secrets + +### Required Secrets (`.github/secrets`) + +| Secret | Used In | Purpose | +|--------|---------|---------| +| `NPM_AUTH_TOKEN` | publish.yml | Authenticate to npm registry for publishing | +| `GITHUB_TOKEN` | All workflows | GitHub API access (auto-provided by GitHub Actions) | +| `SLACK_WEBHOOK_URL` | All workflows | Send failure notifications to Slack | + +### Environment Setup + +- **Node**: v20.x (for npm operations) +- **Ruby**: 3.1 (for version.rb and clean.rb scripts) +- **OpenAPI Generator**: Latest version (installed via npm during workflow) +- **Git**: Configured with `devexperience` bot account for automatic commits + +--- + +## Execution Timelines + +### Automatic Flow Timeline + +``` +OpenAPI Repo: Commits change to v20111101.yml and v20250224.yml + ↓ +repository_dispatch: {"api_versions": "v20111101,v20250224"} + ↓ +generate_publish_release.yml: Triggered + ├─ Matrix[v20111101]: Clean, Bump, Generate (parallel) + ├─ Matrix[v20250224]: Clean, Bump, Generate (parallel) + ├─ Download artifacts + ├─ Update CHANGELOG.md + ├─ Commit to master + ├─ publish[v20111101]: npm publish (parallel) + ├─ publish[v20250224]: npm publish (parallel) + ├─ release[v20111101]: Create tag v2.0.1 (parallel) + ├─ release[v20250224]: Create tag v3.0.1 (parallel) + ↓ +Result: Both versions published and released, CHANGELOG updated +``` + +### Manual Flow Timeline + +``` +Developer: Runs generate.yml (api_version, version_bump) + ↓ +generate.yml: Validate, Bump (if needed), Clean, Generate + ├─ Update CHANGELOG.md + ├─ Create feature branch + ├─ Create Pull Request + ↓ +Code Review: Developer reviews and merges PR + ↓ +on-push-master.yml: Triggered + ├─ check-skip-publish: false + ├─ publish[matching_version]: npm publish + ├─ release[matching_version]: Create tag + ↓ +Result: Selected version published and released +``` + +--- + +## Reference + +For quick guides and troubleshooting, see: +- [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md) - Architecture overview and diagrams +- [Adding-a-New-API-Version.md](Adding-a-New-API-Version.md) - Step-by-step guide for new versions +- [Troubleshooting-Guide.md](Troubleshooting-Guide.md) - Common issues and solutions From af164140f248f699ddd7345c4d2b5cd464424e5a Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Tue, 27 Jan 2026 15:38:33 -0700 Subject: [PATCH 11/11] Migrate SDK from latest/ to v20111101/ [skip-publish] --- {latest => v20111101}/.gitignore | 0 {latest => v20111101}/.npmignore | 0 {latest => v20111101}/.openapi-generator-ignore | 0 {latest => v20111101}/.openapi-generator/FILES | 0 {latest => v20111101}/.openapi-generator/VERSION | 0 {latest => v20111101}/CHANGELOG.md | 0 {latest => v20111101}/LICENSE | 0 {latest => v20111101}/MIGRATION.md | 0 {latest => v20111101}/README.md | 0 {latest => v20111101}/api.ts | 0 {latest => v20111101}/base.ts | 0 {latest => v20111101}/common.ts | 0 {latest => v20111101}/configuration.ts | 0 {latest => v20111101}/git_push.sh | 0 {latest => v20111101}/index.ts | 0 {latest => v20111101}/package.json | 0 {latest => v20111101}/tsconfig.esm.json | 0 {latest => v20111101}/tsconfig.json | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename {latest => v20111101}/.gitignore (100%) rename {latest => v20111101}/.npmignore (100%) rename {latest => v20111101}/.openapi-generator-ignore (100%) rename {latest => v20111101}/.openapi-generator/FILES (100%) rename {latest => v20111101}/.openapi-generator/VERSION (100%) rename {latest => v20111101}/CHANGELOG.md (100%) rename {latest => v20111101}/LICENSE (100%) rename {latest => v20111101}/MIGRATION.md (100%) rename {latest => v20111101}/README.md (100%) rename {latest => v20111101}/api.ts (100%) rename {latest => v20111101}/base.ts (100%) rename {latest => v20111101}/common.ts (100%) rename {latest => v20111101}/configuration.ts (100%) rename {latest => v20111101}/git_push.sh (100%) rename {latest => v20111101}/index.ts (100%) rename {latest => v20111101}/package.json (100%) rename {latest => v20111101}/tsconfig.esm.json (100%) rename {latest => v20111101}/tsconfig.json (100%) diff --git a/latest/.gitignore b/v20111101/.gitignore similarity index 100% rename from latest/.gitignore rename to v20111101/.gitignore diff --git a/latest/.npmignore b/v20111101/.npmignore similarity index 100% rename from latest/.npmignore rename to v20111101/.npmignore diff --git a/latest/.openapi-generator-ignore b/v20111101/.openapi-generator-ignore similarity index 100% rename from latest/.openapi-generator-ignore rename to v20111101/.openapi-generator-ignore diff --git a/latest/.openapi-generator/FILES b/v20111101/.openapi-generator/FILES similarity index 100% rename from latest/.openapi-generator/FILES rename to v20111101/.openapi-generator/FILES diff --git a/latest/.openapi-generator/VERSION b/v20111101/.openapi-generator/VERSION similarity index 100% rename from latest/.openapi-generator/VERSION rename to v20111101/.openapi-generator/VERSION diff --git a/latest/CHANGELOG.md b/v20111101/CHANGELOG.md similarity index 100% rename from latest/CHANGELOG.md rename to v20111101/CHANGELOG.md diff --git a/latest/LICENSE b/v20111101/LICENSE similarity index 100% rename from latest/LICENSE rename to v20111101/LICENSE diff --git a/latest/MIGRATION.md b/v20111101/MIGRATION.md similarity index 100% rename from latest/MIGRATION.md rename to v20111101/MIGRATION.md diff --git a/latest/README.md b/v20111101/README.md similarity index 100% rename from latest/README.md rename to v20111101/README.md diff --git a/latest/api.ts b/v20111101/api.ts similarity index 100% rename from latest/api.ts rename to v20111101/api.ts diff --git a/latest/base.ts b/v20111101/base.ts similarity index 100% rename from latest/base.ts rename to v20111101/base.ts diff --git a/latest/common.ts b/v20111101/common.ts similarity index 100% rename from latest/common.ts rename to v20111101/common.ts diff --git a/latest/configuration.ts b/v20111101/configuration.ts similarity index 100% rename from latest/configuration.ts rename to v20111101/configuration.ts diff --git a/latest/git_push.sh b/v20111101/git_push.sh similarity index 100% rename from latest/git_push.sh rename to v20111101/git_push.sh diff --git a/latest/index.ts b/v20111101/index.ts similarity index 100% rename from latest/index.ts rename to v20111101/index.ts diff --git a/latest/package.json b/v20111101/package.json similarity index 100% rename from latest/package.json rename to v20111101/package.json diff --git a/latest/tsconfig.esm.json b/v20111101/tsconfig.esm.json similarity index 100% rename from latest/tsconfig.esm.json rename to v20111101/tsconfig.esm.json diff --git a/latest/tsconfig.json b/v20111101/tsconfig.json similarity index 100% rename from latest/tsconfig.json rename to v20111101/tsconfig.json