From 021daf69167ad0ee5c2e653edb73e3206afe0ee5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:32:55 +0000 Subject: [PATCH 1/7] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9e3b99b..32f52ad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 138 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-11e1931d767cef402bbed5a965746d1933ae72db0f41881860593a0b1424fd80.yml -openapi_spec_hash: 9def941805f233f8761c4bdae88f6137 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-1ba05406f99c844cf7b32fe80c399017d00c504563f211caf66dfbccf8dd146d.yml +openapi_spec_hash: be1b9b8a351560da21bbe3b53fd04905 config_hash: 6c3a754258f0f77e9032a90a478ab76d From 3e1c7f937cdef899737f99a5b3d5563ce2314ebf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:39:56 +0000 Subject: [PATCH 2/7] feat: Document POST /notifications/{id}/duplicate [C-18607] (#165) * Document POST /notifications/{id}/duplicate [C-18607] Documents the V2 notification template duplicate endpoint added in trycourier/backend#9536 and registers it for SDK generation. - openapi.yml: new /notifications/{id}/duplicate path (post, operationId notifications_duplicate), modeled on the sibling publish endpoint. 201 -> NotificationTemplateResponse, 404 -> NotFound, 422 -> UnprocessableEntity (source is journey- or broadcast-scoped). - stainless.yml: adds duplicate: post /notifications/{id}/duplicate so a duplicate() method generates across the SDKs. Co-Authored-By: Claude Opus 4.8 (1M context) * Use real TypeID-style example IDs + add id-conventions.md The duplicate endpoint example used placeholder IDs (nt_01xyz789, brand_abc, marketing, nt_123, journey_abc) that don't match the TypeID convention the rest of the spec follows. Swap them for real canonical sample IDs (nt_/bnd_/pt_/jry_). Add specs/id-conventions.md documenting the prefix registry (sourced from backend lib/courier-ids/constants.ts), the canonical sample IDs to reuse, and two open questions (journey jry vs jny; brand bnd not yet in the backend registry). Co-Authored-By: Claude Opus 4.8 (1M context) * Move ID conventions from specs/ into an example-ids skill specs/ is for the shipped spec, not editor/agent guidance. Relocate the convention reference to .agents/skills/example-ids/SKILL.md (surfaced via the .claude/.cursor/.codex skills symlinks) so it triggers when editing openapi.yml examples. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- .stats.yml | 8 ++--- pkg/cmd/cmd.go | 1 + pkg/cmd/notification.go | 57 ++++++++++++++++++++++++++++++++++++ pkg/cmd/notification_test.go | 12 ++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 32f52ad..809d9f7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 138 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-1ba05406f99c844cf7b32fe80c399017d00c504563f211caf66dfbccf8dd146d.yml -openapi_spec_hash: be1b9b8a351560da21bbe3b53fd04905 -config_hash: 6c3a754258f0f77e9032a90a478ab76d +configured_endpoints: 139 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-def1e982add0411bf64b48cdf5e4f2c1b85b9bd0ada0d5e6fc4869afa85e0bff.yml +openapi_spec_hash: 5d129cdf800798bcd4a93585ec89c696 +config_hash: dcd58abf1e56b114bdce22336ca3d570 diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 7ae6cea..fbbf72c 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -286,6 +286,7 @@ func init() { ¬ificationsRetrieve, ¬ificationsList, ¬ificationsArchive, + ¬ificationsDuplicate, ¬ificationsListVersions, ¬ificationsPublish, ¬ificationsPutContent, diff --git a/pkg/cmd/notification.go b/pkg/cmd/notification.go index c6b6c92..d84129a 100644 --- a/pkg/cmd/notification.go +++ b/pkg/cmd/notification.go @@ -128,6 +128,21 @@ var notificationsArchive = cli.Command{ HideHelpCommand: true, } +var notificationsDuplicate = cli.Command{ + Name: "duplicate", + Usage: "Duplicate a notification template. Creates a standalone copy within the same\nworkspace and environment, with \" COPY\" appended to the title. The copy clones\nthe source draft's tags, brand, subscription topic, routing strategy, channels,\nand content, and is always created as a standalone template (it is not linked to\nany journey or broadcast, even if the source was). Templates that are scoped to\na journey or a broadcast cannot be duplicated through this endpoint.", + Suggest: true, + Flags: []cli.Flag{ + &requestflag.Flag[string]{ + Name: "id", + Required: true, + PathParam: "id", + }, + }, + Action: handleNotificationsDuplicate, + HideHelpCommand: true, +} + var notificationsListVersions = cli.Command{ Name: "list-versions", Usage: "List versions of a notification template.", @@ -540,6 +555,48 @@ func handleNotificationsArchive(ctx context.Context, cmd *cli.Command) error { return client.Notifications.Archive(ctx, cmd.Value("id").(string), options...) } +func handleNotificationsDuplicate(ctx context.Context, cmd *cli.Command) error { + client := courier.NewClient(getDefaultRequestOptions(cmd)...) + unusedArgs := cmd.Args().Slice() + if !cmd.IsSet("id") && len(unusedArgs) > 0 { + cmd.Set("id", unusedArgs[0]) + unusedArgs = unusedArgs[1:] + } + if len(unusedArgs) > 0 { + return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) + } + + options, err := flagOptions( + cmd, + apiquery.NestedQueryFormatBrackets, + apiquery.ArrayQueryFormatComma, + EmptyBody, + false, + ) + if err != nil { + return err + } + + var res []byte + options = append(options, option.WithResponseBodyInto(&res)) + _, err = client.Notifications.Duplicate(ctx, cmd.Value("id").(string), options...) + if err != nil { + return err + } + + obj := gjson.ParseBytes(res) + format := cmd.Root().String("format") + explicitFormat := cmd.Root().IsSet("format") + transform := cmd.Root().String("transform") + return ShowJSON(obj, ShowJSONOpts{ + ExplicitFormat: explicitFormat, + Format: format, + RawOutput: cmd.Root().Bool("raw-output"), + Title: "notifications duplicate", + Transform: transform, + }) +} + func handleNotificationsListVersions(ctx context.Context, cmd *cli.Command) error { client := courier.NewClient(getDefaultRequestOptions(cmd)...) unusedArgs := cmd.Args().Slice() diff --git a/pkg/cmd/notification_test.go b/pkg/cmd/notification_test.go index 1c7bbb0..27553f0 100644 --- a/pkg/cmd/notification_test.go +++ b/pkg/cmd/notification_test.go @@ -114,6 +114,18 @@ func TestNotificationsArchive(t *testing.T) { }) } +func TestNotificationsDuplicate(t *testing.T) { + t.Skip("Mock server tests are disabled") + t.Run("regular flags", func(t *testing.T) { + mocktest.TestRunMockTestWithFlags( + t, + "--api-key", "string", + "notifications", "duplicate", + "--id", "id", + ) + }) +} + func TestNotificationsListVersions(t *testing.T) { t.Skip("Mock server tests are disabled") t.Run("regular flags", func(t *testing.T) { From 7cd231c7cb4917b51abdc1d2f7d4851a280d8116 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:02:27 +0000 Subject: [PATCH 3/7] feat(stlc): configurable CI runner and private-production-repo support in workflow templates --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2ee0a6..5ea2e37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/courier-cli' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: @@ -48,7 +48,7 @@ jobs: permissions: contents: read id-token: write - runs-on: ${{ github.repository == 'stainless-sdks/courier-cli' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -95,7 +95,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/courier-cli' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From 174b574da450cc229abf4785f4a8c2bd9a7f7adb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:22:15 +0000 Subject: [PATCH 4/7] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 809d9f7..11f22e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 139 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-def1e982add0411bf64b48cdf5e4f2c1b85b9bd0ada0d5e6fc4869afa85e0bff.yml -openapi_spec_hash: 5d129cdf800798bcd4a93585ec89c696 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-15e6e3c944208ca5d7bad9070f5c1e04774bf21e64454244f98e7b9e56baf70b.yml +openapi_spec_hash: 2cc798d9c07f90dd28ab9c92854c7947 config_hash: dcd58abf1e56b114bdce22336ca3d570 From 9a29ba9b45376e4f01153e6b63612259f661512a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:44:38 +0000 Subject: [PATCH 5/7] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 11f22e8..705268e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 139 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-15e6e3c944208ca5d7bad9070f5c1e04774bf21e64454244f98e7b9e56baf70b.yml -openapi_spec_hash: 2cc798d9c07f90dd28ab9c92854c7947 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-3ba276bda58608efe8027da0df37d24407f9995a759aa10e4a6cb201a40e8e4d.yml +openapi_spec_hash: 5e207aa1972d01137897cc20240d2c9d config_hash: dcd58abf1e56b114bdce22336ca3d570 From ce52209b2709c1e7198462fa77fb79014d52a7c6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:45:20 +0000 Subject: [PATCH 6/7] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 705268e..4417498 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 139 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-3ba276bda58608efe8027da0df37d24407f9995a759aa10e4a6cb201a40e8e4d.yml -openapi_spec_hash: 5e207aa1972d01137897cc20240d2c9d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b03f5346718dcd7b22f15893445ea593ab87535c90c540fc5a796c6ecd54d779.yml +openapi_spec_hash: 15677d3be4ecd33eab154080b4bc437f config_hash: dcd58abf1e56b114bdce22336ca3d570 From 61490b03145085941d05f62c06764a7cefc53f1f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:45:41 +0000 Subject: [PATCH 7/7] release: 3.12.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pkg/cmd/version.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 26e35c4..faa0df4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.11.2" + ".": "3.12.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 082dd64..3cccc47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 3.12.0 (2026-07-20) + +Full Changelog: [v3.11.2...v3.12.0](https://github.com/trycourier/courier-cli/compare/v3.11.2...v3.12.0) + +### Features + +* Document POST /notifications/{id}/duplicate [C-18607] ([#165](https://github.com/trycourier/courier-cli/issues/165)) ([3e1c7f9](https://github.com/trycourier/courier-cli/commit/3e1c7f937cdef899737f99a5b3d5563ce2314ebf)) +* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([7cd231c](https://github.com/trycourier/courier-cli/commit/7cd231c7cb4917b51abdc1d2f7d4851a280d8116)) + ## 3.11.2 (2026-07-10) Full Changelog: [v3.11.1...v3.11.2](https://github.com/trycourier/courier-cli/compare/v3.11.1...v3.11.2) diff --git a/pkg/cmd/version.go b/pkg/cmd/version.go index 24bb894..5c0c761 100644 --- a/pkg/cmd/version.go +++ b/pkg/cmd/version.go @@ -2,4 +2,4 @@ package cmd -const Version = "3.11.2" // x-release-please-version +const Version = "3.12.0" // x-release-please-version