From 5f2435dc3126a87f16d7ded87562704d4ee9c4cf Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 13:49:52 +0300 Subject: [PATCH 01/15] ci: add SDK regeneration workflow --- .github/workflows/regen.yml | 146 ++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 .github/workflows/regen.yml diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml new file mode 100644 index 0000000..b166289 --- /dev/null +++ b/.github/workflows/regen.yml @@ -0,0 +1,146 @@ +name: Regenerate SDK + +# Canonical SDK-regen workflow. Copy this file into each SDK repo at +# `.github/workflows/regen.yml`; the only per-SDK customization needed is +# inserting a language toolchain step (e.g. setup-python / setup-go / etc.) +# below the "Toolchain (language SDK)" marker. +# +# Triggers: +# workflow_dispatch — manual run with optional inputs +# repository_dispatch — fired from goodsender-web after spec changes +# (event type: regen-sdk; +# client_payload: spec_url, spec_tag, clean, generator_version) + +on: + workflow_dispatch: + inputs: + spec_url: + description: "URL to download bundled openapi spec from. If empty, regenerate from openapi/goodsender.yaml in repo." + required: false + type: string + clean: + description: "Pass --clean to scripts/regen.sh (full wipe before regen)." + required: false + type: boolean + default: false + generator_version: + description: "Override openapi-generator JAR version (default 7.21.0 from scripts/regen.sh)." + required: false + type: string + repository_dispatch: + types: [regen-sdk] + +permissions: + contents: write + pull-requests: write + +jobs: + regen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # --- Toolchain (regen driver): Node runs the openapi-generator-cli wrapper + - uses: actions/setup-node@v4 + with: + node-version: "20" + + # --- Toolchain (regen driver): Java runs the openapi-generator JAR + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "17" + + # --- Toolchain (language SDK): inserted per repo (Python / Go / Ruby / etc.) + # See per-SDK task in docs/superpowers/plans/2026-05-19-sdk-regen-automation.md + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + working-directory: tests + + - name: Cache openapi-generator JAR + npm + uses: actions/cache@v4 + with: + path: | + ~/.openapi-generator + ~/.npm + key: openapi-gen-${{ runner.os }}-${{ hashFiles('openapitools.json') }} + + - name: Resolve inputs + id: in + env: + DISPATCH_SPEC_URL: ${{ github.event.inputs.spec_url }} + DISPATCH_CLEAN: ${{ github.event.inputs.clean }} + DISPATCH_GEN_VER: ${{ github.event.inputs.generator_version }} + PAYLOAD_SPEC_URL: ${{ github.event.client_payload.spec_url }} + PAYLOAD_SPEC_TAG: ${{ github.event.client_payload.spec_tag }} + PAYLOAD_CLEAN: ${{ github.event.client_payload.clean }} + PAYLOAD_GEN_VER: ${{ github.event.client_payload.generator_version }} + run: | + set -euo pipefail + spec_url="${DISPATCH_SPEC_URL:-${PAYLOAD_SPEC_URL:-}}" + spec_tag="${PAYLOAD_SPEC_TAG:-}" + clean="${DISPATCH_CLEAN:-${PAYLOAD_CLEAN:-false}}" + gen_ver="${DISPATCH_GEN_VER:-${PAYLOAD_GEN_VER:-}}" + [[ "$clean" != "true" ]] && clean="false" + { + echo "spec_url<> "$GITHUB_OUTPUT" + + - name: Update spec from URL + if: steps.in.outputs.spec_url != '' + env: + SPEC_URL: ${{ steps.in.outputs.spec_url }} + run: | + set -euo pipefail + curl --fail --location --show-error --silent "$SPEC_URL" -o openapi/goodsender.yaml + + - name: Regenerate + env: + OPENAPI_GENERATOR_VERSION: ${{ steps.in.outputs.gen_ver }} + CLEAN: ${{ steps.in.outputs.clean }} + run: | + set -euo pipefail + if [[ "$CLEAN" == "true" ]]; then + bash scripts/regen.sh --clean + else + bash scripts/regen.sh + fi + + - name: Run conformance tests (mock) + id: tests + continue-on-error: true + run: bash tests/run.sh mock + + - name: Detect changes + id: diff + run: | + if [[ -z "$(git status --porcelain)" ]]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + git --no-pager diff --stat | tee -a "$GITHUB_STEP_SUMMARY" + fi + + - name: Open PR + if: steps.diff.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v6 + with: + commit-message: "chore: regenerate SDK from openapi spec ${{ steps.in.outputs.spec_tag || 'in-repo' }}" + title: "chore: regenerate SDK from openapi spec ${{ steps.in.outputs.spec_tag || 'in-repo' }}" + body: | + Automated regeneration via `.github/workflows/regen.yml`. + + - Trigger: `${{ github.event_name }}` + - Spec tag: `${{ steps.in.outputs.spec_tag || '(none — in-repo spec used)' }}` + - Spec URL: `${{ steps.in.outputs.spec_url || '(none)' }}` + - Clean: `${{ steps.in.outputs.clean }}` + - Generator version: `${{ steps.in.outputs.gen_ver || '(default from scripts/regen.sh)' }}` + - Conformance tests (`tests/run.sh mock`): **${{ steps.tests.outcome }}** + branch: auto/regen-${{ github.run_id }} + delete-branch: true + labels: automated, regen From 57f17da1412fd5ac3a892f55335cd38eb10ec3f8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 20:36:14 +0300 Subject: [PATCH 02/15] ci: allow workflow to fire on push to ci/** branches --- .github/workflows/regen.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index b166289..2a72c2a 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -29,6 +29,11 @@ on: type: string repository_dispatch: types: [regen-sdk] + # Test trigger: pushes to any `ci/**` branch run this workflow on the branch's code, + # so regen + tests + PR creation can be smoke-tested before merging to main. + push: + branches: + - 'ci/**' permissions: contents: write From 2e25d4af1db233586c50f001a486662e72ca6c80 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 20:58:27 +0300 Subject: [PATCH 03/15] ci: re-trigger workflow after enabling PR permission From 5a207f98dc38a17c320dd642b23d8439eedd3aba Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 08:28:25 +0300 Subject: [PATCH 04/15] ci: open regen PRs via GitHub App token instead of GITHUB_TOKEN --- .github/workflows/regen.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 2a72c2a..60a421e 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -131,10 +131,19 @@ jobs: git --no-pager diff --stat | tee -a "$GITHUB_STEP_SUMMARY" fi + - name: Mint PR-creation token from GitHub App + if: steps.diff.outputs.changed == 'true' + id: pr_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.SDK_DISPATCH_APP_ID }} + private-key: ${{ secrets.SDK_DISPATCH_APP_PRIVATE_KEY }} + - name: Open PR if: steps.diff.outputs.changed == 'true' uses: peter-evans/create-pull-request@v6 with: + token: ${{ steps.pr_token.outputs.token }} commit-message: "chore: regenerate SDK from openapi spec ${{ steps.in.outputs.spec_tag || 'in-repo' }}" title: "chore: regenerate SDK from openapi spec ${{ steps.in.outputs.spec_tag || 'in-repo' }}" body: | From 7eac1519de1414dc85135a85e8d4389f1097c941 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 08:39:49 +0300 Subject: [PATCH 05/15] ci: re-trigger after org secrets in place From 1d7e7c0c23dce5909985885cb2cc408197851fd5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 10:16:01 +0300 Subject: [PATCH 06/15] ci: introduce .regen-ignore as single source of truth for preserved paths --- .regen-ignore | 21 +++++++++++++++++++++ scripts/regen.sh | 42 +++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 .regen-ignore diff --git a/.regen-ignore b/.regen-ignore new file mode 100644 index 0000000..a0a000a --- /dev/null +++ b/.regen-ignore @@ -0,0 +1,21 @@ +# Files preserved across regenerations. +# scripts/regen.sh consumes this file in two ways: +# 1. Filtered (comments + blank lines stripped) and written to +# .openapi-generator-ignore, which openapi-generator reads to know +# which paths it must NOT overwrite. +# 2. The first path component of every pattern is added to --clean's +# preserve list, so `regen.sh --clean` will not wipe these top-level +# directories or files. +# +# Patterns are gitignore-style. Lines starting with `#` and blank lines are +# treated as comments. + +LICENSE +CHANGELOG.md +README.md +tests/** +scripts/** +openapi/** +openapitools.json +.github/** +.regen-ignore diff --git a/scripts/regen.sh b/scripts/regen.sh index 4229a84..b8219e0 100755 --- a/scripts/regen.sh +++ b/scripts/regen.sh @@ -34,31 +34,27 @@ export OPENAPI_GENERATOR_VERSION="${OPENAPI_GENERATOR_VERSION:-7.21.0}" [[ -f "$SPEC" ]] || { echo "!! spec not found at $SPEC" >&2; exit 1; } [[ -f "$CONFIG" ]] || { echo "!! generator config not found at $CONFIG" >&2; exit 1; } -# --- .openapi-generator-ignore: protect hand-curated files from being overwritten -cat > "$SDK_DIR/.openapi-generator-ignore" <<'IGNORE_EOF' -LICENSE -CHANGELOG.md -README.md -tests/** -scripts/** -openapi/** -openapitools.json -IGNORE_EOF +# --- Sync .openapi-generator-ignore from .regen-ignore +# .regen-ignore is the single source of truth for preserved paths. We filter +# comments + blanks and write the result to .openapi-generator-ignore (which +# openapi-generator reads). The same patterns drive --clean's preserve list. +REGEN_IGNORE="$SDK_DIR/.regen-ignore" +[[ -f "$REGEN_IGNORE" ]] || { echo "!! .regen-ignore not found at $REGEN_IGNORE" >&2; exit 1; } +grep -v '^[[:space:]]*#' "$REGEN_IGNORE" | grep -v '^[[:space:]]*$' > "$SDK_DIR/.openapi-generator-ignore" -# --- Optional clean step: wipe SDK output (preserves hand-curated files only) +# --- Optional clean step: wipe SDK output (preserves entries in .regen-ignore) if (( CLEAN == 1 )); then - echo ">> --clean: wiping $SDK_DIR (preserving LICENSE, CHANGELOG.md, README.md, tests/, scripts/, openapi/, openapitools.json)" - find "$SDK_DIR" -mindepth 1 -maxdepth 1 \ - ! -name LICENSE \ - ! -name CHANGELOG.md \ - ! -name README.md \ - ! -name tests \ - ! -name scripts \ - ! -name openapi \ - ! -name openapitools.json \ - ! -name .git \ - ! -name .gitignore \ - -exec rm -rf {} + + preserve_args=() + while IFS= read -r line; do + line="${line%%#*}" + line="$(echo "$line" | xargs)" + [[ -z "$line" ]] && continue + top="${line%%/*}" + preserve_args+=(! -name "$top") + done < "$REGEN_IGNORE" + preserve_args+=(! -name .git ! -name .gitignore) + echo ">> --clean: wiping $SDK_DIR (preserving entries from .regen-ignore)" + find "$SDK_DIR" -mindepth 1 -maxdepth 1 "${preserve_args[@]}" -exec rm -rf {} + fi # --- Regen via openapi-generator-cli From 28616a7bc12375dc166158cf45b3a15589d6865a Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 11:29:05 +0300 Subject: [PATCH 07/15] ci: fail workflow when conformance tests fail (gate for backward-compat) --- .github/workflows/regen.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 60a421e..6e36999 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -158,3 +158,11 @@ jobs: branch: auto/regen-${{ github.run_id }} delete-branch: true labels: automated, regen + + - name: Fail workflow if conformance tests failed + if: always() && steps.tests.outcome == 'failure' + run: | + echo "Conformance tests failed — see the 'Run conformance tests (mock)' step above." + echo "The regen PR (if any diff existed) has still been opened so the change is visible for review." + echo "This workflow run is marked failed so the failure surfaces on the PR's checks list." + exit 1 From 9b91a710a78abfb789261f3291be662e0d447dd1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 12:34:27 +0300 Subject: [PATCH 08/15] ci: use stable auto/regen branch so regen PR is updated in place --- .github/workflows/regen.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 6e36999..e63fbdd 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -155,7 +155,7 @@ jobs: - Clean: `${{ steps.in.outputs.clean }}` - Generator version: `${{ steps.in.outputs.gen_ver || '(default from scripts/regen.sh)' }}` - Conformance tests (`tests/run.sh mock`): **${{ steps.tests.outcome }}** - branch: auto/regen-${{ github.run_id }} + branch: auto/regen delete-branch: true labels: automated, regen From 7703a2a11532228584f9a6db1ec052e35cc9311c Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 12:44:37 +0300 Subject: [PATCH 09/15] docs: rewrite README with concise install + usage examples --- README.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4add236 --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# GoodSender SDK for Ruby + +Official client library for the GoodSender email API. Gem: `goodsender` + +## Installation + +```bash +gem install goodsender +``` + +Or in your `Gemfile`: + +```ruby +gem 'goodsender' +``` + +## Quick start + +```ruby +require 'goodsender' + +GoodSender.configure do |c| + c.scheme = 'https' + c.host = 'api.goodsender.com' + c.base_path = '' + c.access_token = 'YOUR_API_KEY' +end + +emails = GoodSender::EmailsApi.new +domains = GoodSender::DomainsApi.new + +req = GoodSender::SendEmailRequest.new(emails: [ + GoodSender::SendEmail.new( + from: GoodSender::Address.new(email: 'sender@example.com'), + to: [GoodSender::Address.new(email: 'recipient@example.com')], + subject: 'Hello', + text_content: 'Body' + ) +]) +res = emails.send_email(req) +puts "sent=#{res.sent} declined=#{res.declined}" +``` + +## Examples + +### Send via a template + +```ruby +req = GoodSender::TemplateEmailRequest.new( + from: GoodSender::Address.new(email: 'sender@example.com'), + to: GoodSender::Address.new(email: 'recipient@example.com'), + subject: 'Your OTP', + template: GoodSender::TemplateEmailRequestTemplate.new( + template_id: 'otp_code', + variables: { 'code' => '123456' } + ) +) +res = emails.send_template_email(req) +puts "status=#{res.status}" +``` + +### List domains + +```ruby +res = domains.list_domains(limit: 50) +puts "domains=#{res.domains.length}" +``` + +### Check consent status + +```ruby +res = emails.get_email_consent_status('user@example.com', domain: 'example.com') +puts "entries=#{res.length}" + +# List all consents for a domain +res = emails.list_email_consents('example.com', limit: 50) +puts "emails=#{(res.emails || []).length}" +``` + +## Documentation + +- API reference: +- OpenAPI spec: `openapi/goodsender.yaml` in this repo +- Conformance tests: `tests/` + +## Development + +- Regenerate from spec: `scripts/regen.sh` (preserves `tests/`, `.github/`, and hand-curated files per `.regen-ignore`) +- Run conformance tests against local mock: `tests/run.sh mock` +- Run conformance against real dev API: `tests/run.sh dev` (requires `tests/.env.dev`) + +## License + +MIT — see [LICENSE](LICENSE). From 99ed5cb7f4c9e3db2f0ada5211b71b07ec1e5045 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 12:47:32 +0300 Subject: [PATCH 10/15] ci: bump actions/checkout to v6 --- .github/workflows/regen.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index e63fbdd..5d0e72c 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -43,7 +43,7 @@ jobs: regen: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 # --- Toolchain (regen driver): Node runs the openapi-generator-cli wrapper - uses: actions/setup-node@v4 From a67e8705b1bf228d3253b0b0183214d0ba37f254 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 12:51:57 +0300 Subject: [PATCH 11/15] ci: disable checkout credential persistence (avoid duplicate Authorization header) --- .github/workflows/regen.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 5d0e72c..73e3d90 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -44,6 +44,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false # --- Toolchain (regen driver): Node runs the openapi-generator-cli wrapper - uses: actions/setup-node@v4 From d2357d323835ea4cad9160d9f5167519b0d1ae5e Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 May 2026 22:45:31 +0300 Subject: [PATCH 12/15] ci: authenticate spec download with App token (inboxbit/goodsender-web is private) --- .github/workflows/regen.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 73e3d90..471963f 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -98,13 +98,26 @@ jobs: echo "gen_ver<> "$GITHUB_OUTPUT" + - name: Mint download token from GitHub App + if: steps.in.outputs.spec_url != '' + id: download_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.SDK_DISPATCH_APP_ID }} + private-key: ${{ secrets.SDK_DISPATCH_APP_PRIVATE_KEY }} + owner: inboxbit + repositories: goodsender-web + - name: Update spec from URL if: steps.in.outputs.spec_url != '' env: SPEC_URL: ${{ steps.in.outputs.spec_url }} + DOWNLOAD_TOKEN: ${{ steps.download_token.outputs.token }} run: | set -euo pipefail - curl --fail --location --show-error --silent "$SPEC_URL" -o openapi/goodsender.yaml + curl --fail --location --show-error --silent \ + -H "Authorization: Bearer $DOWNLOAD_TOKEN" \ + "$SPEC_URL" -o openapi/goodsender.yaml - name: Regenerate env: From ed4bc7466ff4ac8f1d9d4f1ee55f56683bcbd64e Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 May 2026 22:52:31 +0300 Subject: [PATCH 13/15] ci: mask private spec URL from logs and strip it from PR body --- .github/workflows/regen.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 471963f..9dbff37 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -77,17 +77,20 @@ jobs: - name: Resolve inputs id: in env: - DISPATCH_SPEC_URL: ${{ github.event.inputs.spec_url }} + # Note: spec_url is intentionally NOT in this env block. It comes from a + # private repo's release URL and should not appear in step env-logging. + # Instead we jq it out of $GITHUB_EVENT_PATH and immediately add-mask it. DISPATCH_CLEAN: ${{ github.event.inputs.clean }} DISPATCH_GEN_VER: ${{ github.event.inputs.generator_version }} - PAYLOAD_SPEC_URL: ${{ github.event.client_payload.spec_url }} - PAYLOAD_SPEC_TAG: ${{ github.event.client_payload.spec_tag }} PAYLOAD_CLEAN: ${{ github.event.client_payload.clean }} PAYLOAD_GEN_VER: ${{ github.event.client_payload.generator_version }} run: | set -euo pipefail - spec_url="${DISPATCH_SPEC_URL:-${PAYLOAD_SPEC_URL:-}}" - spec_tag="${PAYLOAD_SPEC_TAG:-}" + spec_url=$(jq -r '.inputs.spec_url // .client_payload.spec_url // ""' "$GITHUB_EVENT_PATH") + spec_tag=$(jq -r '.client_payload.spec_tag // ""' "$GITHUB_EVENT_PATH") + if [[ -n "$spec_url" ]]; then + echo "::add-mask::$spec_url" + fi clean="${DISPATCH_CLEAN:-${PAYLOAD_CLEAN:-false}}" gen_ver="${DISPATCH_GEN_VER:-${PAYLOAD_GEN_VER:-}}" [[ "$clean" != "true" ]] && clean="false" @@ -166,7 +169,6 @@ jobs: - Trigger: `${{ github.event_name }}` - Spec tag: `${{ steps.in.outputs.spec_tag || '(none — in-repo spec used)' }}` - - Spec URL: `${{ steps.in.outputs.spec_url || '(none)' }}` - Clean: `${{ steps.in.outputs.clean }}` - Generator version: `${{ steps.in.outputs.gen_ver || '(default from scripts/regen.sh)' }}` - Conformance tests (`tests/run.sh mock`): **${{ steps.tests.outcome }}** From deb6c33480d254a6cebdb624e93c360f64dee423 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 22 May 2026 15:16:43 +0300 Subject: [PATCH 14/15] ci: use 'gh release download' to fetch spec (handles redirect auth correctly) --- .github/workflows/regen.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 9dbff37..1678a87 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -111,16 +111,17 @@ jobs: owner: inboxbit repositories: goodsender-web - - name: Update spec from URL + - name: Download spec from release if: steps.in.outputs.spec_url != '' env: - SPEC_URL: ${{ steps.in.outputs.spec_url }} - DOWNLOAD_TOKEN: ${{ steps.download_token.outputs.token }} + SPEC_TAG: ${{ steps.in.outputs.spec_tag }} + GH_TOKEN: ${{ steps.download_token.outputs.token }} run: | set -euo pipefail - curl --fail --location --show-error --silent \ - -H "Authorization: Bearer $DOWNLOAD_TOKEN" \ - "$SPEC_URL" -o openapi/goodsender.yaml + gh release download "$SPEC_TAG" \ + --repo inboxbit/goodsender-web \ + --pattern goodsender.yaml \ + --output openapi/goodsender.yaml - name: Regenerate env: From 169bc8d3979b4044e74bee7dce6add9c51a76ae0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 22 May 2026 15:53:45 +0300 Subject: [PATCH 15/15] ci: parameterize spec source repo via SDK_SPEC_REPO secret --- .github/workflows/regen.yml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/regen.yml b/.github/workflows/regen.yml index 1678a87..99b7eb8 100644 --- a/.github/workflows/regen.yml +++ b/.github/workflows/regen.yml @@ -101,6 +101,29 @@ jobs: echo "gen_ver<> "$GITHUB_OUTPUT" + - name: Resolve spec source repo from SDK_SPEC_REPO secret + if: steps.in.outputs.spec_url != '' + id: spec_repo + env: + SDK_SPEC_REPO: ${{ secrets.SDK_SPEC_REPO }} + run: | + set -euo pipefail + if [[ -z "$SDK_SPEC_REPO" ]]; then + echo "!! SDK_SPEC_REPO secret is not set (expected: owner/repo)" >&2 + exit 1 + fi + if [[ "$SDK_SPEC_REPO" != */* ]]; then + echo "!! SDK_SPEC_REPO must be in 'owner/repo' format" >&2 + exit 1 + fi + owner="${SDK_SPEC_REPO%%/*}" + repo="${SDK_SPEC_REPO##*/}" + # Mask both halves so neither appears in any later log + echo "::add-mask::$owner" + echo "::add-mask::$repo" + echo "owner=$owner" >> "$GITHUB_OUTPUT" + echo "repo=$repo" >> "$GITHUB_OUTPUT" + - name: Mint download token from GitHub App if: steps.in.outputs.spec_url != '' id: download_token @@ -108,18 +131,19 @@ jobs: with: app-id: ${{ secrets.SDK_DISPATCH_APP_ID }} private-key: ${{ secrets.SDK_DISPATCH_APP_PRIVATE_KEY }} - owner: inboxbit - repositories: goodsender-web + owner: ${{ steps.spec_repo.outputs.owner }} + repositories: ${{ steps.spec_repo.outputs.repo }} - name: Download spec from release if: steps.in.outputs.spec_url != '' env: SPEC_TAG: ${{ steps.in.outputs.spec_tag }} + SPEC_REPO: ${{ secrets.SDK_SPEC_REPO }} GH_TOKEN: ${{ steps.download_token.outputs.token }} run: | set -euo pipefail gh release download "$SPEC_TAG" \ - --repo inboxbit/goodsender-web \ + --repo "$SPEC_REPO" \ --pattern goodsender.yaml \ --output openapi/goodsender.yaml