diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 58181ff..204f2cb 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,12 +1,21 @@ name: Release Please + +# `next` accumulates validated SDK changes in one versioned PR to `main`. +# Merging that PR creates the GitHub release; the package publishing workflow +# runs from the release event. on: push: branches: + - next - main permissions: contents: read +concurrency: + group: release-please + cancel-in-progress: false + jobs: release-please: if: github.repository == 'kernel/hypeman-ts' @@ -26,7 +35,68 @@ jobs: permission-pull-requests: write permission-workflows: write - - uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1 - id: release + - name: Set up Node + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: '18.20.2' + + - name: Set up pnpm + uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 with: - token: ${{ steps.release-token.outputs.token }} + version: '9.11.0' + run_install: false + + - name: Build pinned release tooling + id: tooling + env: + RELEASE_PLEASE_DIR: ${{ runner.temp }}/release-please + RELEASE_PLEASE_SHA: a116e1e520e0f87824acf46a2e79c91d41e819d7 + run: | + set -euo pipefail + rm -rf "$RELEASE_PLEASE_DIR" + git init "$RELEASE_PLEASE_DIR" + git -C "$RELEASE_PLEASE_DIR" remote add origin https://github.com/stainless-api/release-please.git + git -C "$RELEASE_PLEASE_DIR" fetch --depth=1 origin "$RELEASE_PLEASE_SHA" + git -C "$RELEASE_PLEASE_DIR" checkout --detach FETCH_HEAD + pnpm --dir "$RELEASE_PLEASE_DIR" install --frozen-lockfile + pnpm --dir "$RELEASE_PLEASE_DIR" build + echo "cli=$RELEASE_PLEASE_DIR/build/src/bin/release-please.js" >> "$GITHUB_OUTPUT" + + - name: Open or update the release PR + if: github.ref_name == 'next' + env: + GH_TOKEN: ${{ steps.release-token.outputs.token }} + RELEASE_PLEASE: ${{ steps.tooling.outputs.cli }} + run: | + set -euo pipefail + node "$RELEASE_PLEASE" release-pr \ + --repo-url "$GITHUB_REPOSITORY" \ + --token "$GH_TOKEN" \ + --target-branch main \ + --changes-branch next + + - name: Remove the legacy promotion PR + if: github.ref_name == 'next' + env: + GH_TOKEN: ${{ steps.release-token.outputs.token }} + run: | + set -euo pipefail + legacy=$(gh pr list --repo "$GITHUB_REPOSITORY" --head stainless/release \ + --state open --json number --jq '.[].number') + for pr in $legacy; do + gh pr close "$pr" --repo "$GITHUB_REPOSITORY" \ + --comment "Superseded by the versioned release PR from next to main." + done + gh api -X DELETE "repos/$GITHUB_REPOSITORY/git/refs/heads/stainless/release" >/dev/null 2>&1 || true + + - name: Create the GitHub release + if: github.ref_name == 'main' + env: + GH_TOKEN: ${{ steps.release-token.outputs.token }} + RELEASE_PLEASE: ${{ steps.tooling.outputs.cli }} + run: | + set -euo pipefail + node "$RELEASE_PLEASE" github-release \ + --repo-url "$GITHUB_REPOSITORY" \ + --token "$GH_TOKEN" \ + --target-branch main diff --git a/.github/workflows/stlc-promote.yml b/.github/workflows/stlc-promote.yml index ef14673..b507392 100644 --- a/.github/workflows/stlc-promote.yml +++ b/.github/workflows/stlc-promote.yml @@ -1,8 +1,12 @@ -name: Promote SDKs +name: Promote SDK changes -# Manually fast-forwards production main to the reviewed staging main. The -# ancestor check refuses divergent histories; this workflow never force-pushes. +# Staging is the generator's integration history. Production `next` is the +# developer-facing queue for the next release. This workflow combines the +# latest released state with validated staging changes, then advances `next`. +# Release automation maintains the single versioned PR from `next` to `main`. on: + push: + branches: [main] workflow_dispatch: {} permissions: @@ -12,7 +16,9 @@ jobs: promote: if: github.repository == 'kernel/hypeman-ts-staging' runs-on: ${{ vars.STLC_RUNNER || 'ubuntu-latest' }} - environment: production + concurrency: + group: stlc-promote + cancel-in-progress: true steps: - name: Check out staging uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -29,33 +35,99 @@ jobs: owner: kernel repositories: hypeman-ts permission-contents: write + permission-pull-requests: write permission-workflows: write - - name: Fetch production main + - name: Fetch production branches + id: production env: GH_TOKEN: ${{ steps.production-token.outputs.token }} PRODUCTION_REPO: kernel/hypeman-ts run: | - git remote add production "https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git" + set -euo pipefail + git remote add production \ + "https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git" git fetch production main - - - name: Check whether production already has staging's content - id: diff - run: | - MERGED=$(git merge-tree --write-tree production/main origin/main) || MERGED=conflict - PRODUCTION_TREE=$(git rev-parse 'production/main^{tree}') - if [ "$MERGED" = "$PRODUCTION_TREE" ]; then - echo "Production already contains staging's content. Nothing to promote." - echo "synced=true" >> "$GITHUB_OUTPUT" + if git ls-remote --exit-code --heads production next >/dev/null 2>&1; then + git fetch production next + echo "has_next=true" >> "$GITHUB_OUTPUT" else - echo "synced=false" >> "$GITHUB_OUTPUT" + echo "has_next=false" >> "$GITHUB_OUTPUT" fi - - name: Promote staging to production - if: steps.diff.outputs.synced == 'false' + - name: Prepare the next release branch + env: + APP_SLUG: ${{ steps.production-token.outputs.app-slug }} + GH_TOKEN: ${{ steps.production-token.outputs.token }} + HAS_NEXT: ${{ steps.production.outputs.has_next }} + PRODUCTION_REPO: kernel/hypeman-ts run: | - if ! git merge-base --is-ancestor production/main origin/main; then - echo "::error title=Promote blocked::production/main is not an ancestor of staging main. Back-sync production first." + set -euo pipefail + bot_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) + git config user.name "${APP_SLUG}[bot]" + git config user.email "${bot_id}+${APP_SLUG}[bot]@users.noreply.github.com" + + open_conflict_pr() { + source_ref=$1 + source_name=$2 + advance_next=$3 + conflict_branch=stlc/promotion-conflict + + git merge --abort + existing=$(gh pr list --repo "$PRODUCTION_REPO" --base next \ + --head "$conflict_branch" --state open --json url --jq '.[0].url // ""') + if [ -n "$existing" ]; then + echo "::error title=SDK promotion blocked::Resolve the existing recovery PR: $existing" + exit 1 + fi + + if [ "$advance_next" = "true" ]; then + git push production HEAD:refs/heads/next + fi + git push production "$source_ref:refs/heads/$conflict_branch" --force + + body=$(mktemp) + printf '%s\n' \ + '## SDK promotion conflict' \ + '' \ + "The automated promotion could not merge $source_name into the pending next release." \ + '' \ + 'Resolve the conflicts on this branch, validate the SDK, mark this PR ready, and merge it with a merge commit.' \ + '' \ + 'After merging, rerun the staging Promote SDK changes workflow to include any newer generated changes.' \ + > "$body" + recovery_url=$(gh pr create --repo "$PRODUCTION_REPO" --draft \ + --base next --head "$conflict_branch" \ + --title 'chore: resolve SDK promotion conflict' --body-file "$body") + echo "::error title=SDK promotion conflict::Resolve the recovery PR: $recovery_url" exit 1 + } + + if [ "$HAS_NEXT" = "true" ]; then + git checkout -B stlc/promote-next production/next + else + git checkout -B stlc/promote-next production/main + fi + + if ! git merge-base --is-ancestor production/main HEAD; then + if ! git merge --no-edit production/main; then + open_conflict_pr production/main 'production main' false + fi + fi + if ! git merge-base --is-ancestor origin/main HEAD; then + if ! git merge --no-edit origin/main; then + open_conflict_pr origin/main 'validated staging changes' true + fi + fi + + if [ "$HAS_NEXT" = "true" ]; then + git merge-base --is-ancestor production/next HEAD fi - git push production origin/main:refs/heads/main + + - name: Update the pending release + env: + GH_TOKEN: ${{ steps.production-token.outputs.token }} + run: | + set -euo pipefail + git push production HEAD:refs/heads/next + echo "Updated production next; the versioned release PR will be opened or refreshed." diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 210d290..bcd0522 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.1" + ".": "0.6.0" } diff --git a/.stats.yml b/.stats.yml index b4620cc..1c9b72d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 58 +configured_endpoints: 61 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0df5e4a..1b98d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.6.0](https://github.com/kernel/hypeman-ts/compare/v0.5.1...v0.6.0) (2026-08-12) + + +### Features + +* Add QEMU microvm hypervisor backend ([f8c18cf](https://github.com/kernel/hypeman-ts/commit/f8c18cf81953831bf2464f08c9e19a918ffdfb0c)) +* Add request header authorization to ingress rules ([2fb6855](https://github.com/kernel/hypeman-ts/commit/2fb68550870bace083b8636cc32e5d92255e527b)) +* chore(stlc): seal custom-code tracking files ([fd74279](https://github.com/kernel/hypeman-ts/commit/fd74279abdea5b466a4c5b031150aba1b0d0cdc0)) + ## 0.5.1 (2026-08-06) Full Changelog: [v0.5.0...v0.5.1](https://github.com/kernel/hypeman-ts/compare/v0.5.0...v0.5.1) diff --git a/api.md b/api.md index 5d6015f..8328676 100644 --- a/api.md +++ b/api.md @@ -221,3 +221,19 @@ Methods: - client.builds.cancel(id) -> void - client.builds.events(id, { ...params }) -> BuildEvent - client.builds.get(id) -> Build + +# Pushes + +Types: + +- CreatePushRequest +- Push +- PushCredentials +- PushStatus +- PushListResponse + +Methods: + +- client.pushes.create({ ...params }) -> Push +- client.pushes.list() -> PushListResponse +- client.pushes.get(id) -> Push diff --git a/package-lock.json b/package-lock.json index 97d067e..f8ffb73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@onkernel/hypeman", - "version": "0.5.1", + "version": "0.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@onkernel/hypeman", - "version": "0.5.1", + "version": "0.6.0", "license": "Apache-2.0", "dependencies": { "dockerode": "^4.0.10", diff --git a/package.json b/package.json index e509909..971dfb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onkernel/hypeman", - "version": "0.5.1", + "version": "0.6.0", "description": "The official TypeScript library for the Hypeman API", "author": "Hypeman <>", "types": "dist/index.d.ts", diff --git a/release-please-config.json b/release-please-config.json index 9f17a90..ad933a9 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -10,6 +10,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": false, "pull-request-header": "Automated Release PR", + "pull-request-footer": "Merge this pull request with a merge commit. Merging creates the GitHub release and publishes the package.", "pull-request-title-pattern": "release: ${version}", "changelog-sections": [ { diff --git a/src/client.ts b/src/client.ts index c177b78..a7f4306 100644 --- a/src/client.ts +++ b/src/client.ts @@ -59,6 +59,15 @@ import { IngressTarget, Ingresses, } from './resources/ingresses'; +import { + CreatePushRequest, + Push, + PushCreateParams, + PushCredentials, + PushListResponse, + PushStatus, + Pushes, +} from './resources/pushes'; import { DiskBreakdown, GPUProfile, @@ -850,6 +859,7 @@ export class Hypeman { resources: API.Resources = new API.Resources(this); builders: API.Builders = new API.Builders(this); builds: API.Builds = new API.Builds(this); + pushes: API.Pushes = new API.Pushes(this); } Hypeman.Health = Health; @@ -861,6 +871,7 @@ Hypeman.Devices = Devices; Hypeman.Ingresses = Ingresses; Hypeman.Builders = Builders; Hypeman.Builds = Builds; +Hypeman.Pushes = Pushes; export declare namespace Hypeman { export type RequestOptions = Opts.RequestOptions; @@ -987,5 +998,15 @@ export declare namespace Hypeman { type BuildEventsParams as BuildEventsParams, }; + export { + Pushes as Pushes, + type CreatePushRequest as CreatePushRequest, + type Push as Push, + type PushCredentials as PushCredentials, + type PushStatus as PushStatus, + type PushListResponse as PushListResponse, + type PushCreateParams as PushCreateParams, + }; + export type SnapshotCompressionConfig = API.SnapshotCompressionConfig; } diff --git a/src/resources/index.ts b/src/resources/index.ts index e739a7a..2a60e3b 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -83,6 +83,15 @@ export { type InstanceStatParams, type InstanceWaitParams, } from './instances/instances'; +export { + Pushes, + type CreatePushRequest, + type Push, + type PushCredentials, + type PushStatus, + type PushListResponse, + type PushCreateParams, +} from './pushes'; export { Resources, type DiskBreakdown, diff --git a/src/resources/ingresses.ts b/src/resources/ingresses.ts index f094962..17ef499 100644 --- a/src/resources/ingresses.ts +++ b/src/resources/ingresses.ts @@ -127,12 +127,32 @@ export interface IngressRule { */ redirect_http?: boolean; + request_header_auth?: IngressRule.RequestHeaderAuth; + /** * Enable TLS termination (certificate auto-issued via ACME). */ tls?: boolean; } +export namespace IngressRule { + export interface RequestHeaderAuth { + /** + * Dedicated request header that must match before proxying. Reserved + * authentication, cookie, host, framing, proxy, and hop-by-hop headers are not + * allowed. + */ + header: string; + + /** + * Exact header value required before proxying. This sensitive value is persisted + * and returned by the API like instance environment variables; clients should hide + * it by default. + */ + value: string; + } +} + export interface IngressTarget { /** * Target instance name, ID, or capture reference. diff --git a/src/resources/instances/instances.ts b/src/resources/instances/instances.ts index 141b6ac..5e6f30c 100644 --- a/src/resources/instances/instances.ts +++ b/src/resources/instances/instances.ts @@ -530,9 +530,9 @@ export interface Instance { hotplug_size?: string; /** - * Hypervisor running this instance + * Hypervisor backend running this instance */ - hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; /** * Network configuration of the instance @@ -1110,9 +1110,12 @@ export interface InstanceCreateParams { hotplug_size?: string; /** - * Hypervisor to use for this instance. Defaults to server configuration. + * Hypervisor backend to use for this instance. qemu uses the architecture-native + * standard board; qemu-microvm uses QEMU's minimal Linux amd64 board and does not + * support PCI devices, hotplug memory, or more than eight virtio-mmio devices. + * Defaults to server configuration. */ - hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; /** * Network configuration for the instance diff --git a/src/resources/instances/snapshots.ts b/src/resources/instances/snapshots.ts index 758c825..d7aa71d 100644 --- a/src/resources/instances/snapshots.ts +++ b/src/resources/instances/snapshots.ts @@ -83,7 +83,7 @@ export interface SnapshotRestoreParams { * Body param: Optional hypervisor override. Allowed only when restoring from a * Stopped snapshot. Standby snapshots must restore with their original hypervisor. */ - target_hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + target_hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; /** * Body param: Optional final state after restore. Defaults by snapshot kind: diff --git a/src/resources/pushes.ts b/src/resources/pushes.ts new file mode 100644 index 0000000..38a4488 --- /dev/null +++ b/src/resources/pushes.ts @@ -0,0 +1,180 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; + +export class Pushes extends APIResource { + /** + * Creates a push job that exports a hypeman image from the local OCI cache to a + * remote registry (e.g. AWS ECR, Docker Hub). Only images in the ready state can + * be pushed. + * + * @example + * ```ts + * const push = await client.pushes.create({ + * image: 'docker.io/library/alpine:latest', + * target: + * '123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:v1', + * }); + * ``` + */ + create(body: PushCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/pushes', { body, ...options }); + } + + /** + * Lists outbound image push jobs, newest first. + * + * @example + * ```ts + * const pushes = await client.pushes.list(); + * ``` + */ + list(options?: RequestOptions): APIPromise { + return this._client.get('/pushes', options); + } + + /** + * Get push details + * + * @example + * ```ts + * const push = await client.pushes.get('id'); + * ``` + */ + get(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/pushes/${id}`, options); + } +} + +export interface CreatePushRequest { + /** + * Hypeman image name to push (tag or digest form) + */ + image: string; + + /** + * Full remote reference to push to + */ + target: string; + + /** + * Registry credentials borrowed for this push only. When omitted, the server's own + * registry credentials are used. + */ + credentials?: PushCredentials; + + /** + * Allow pushing to plain-HTTP registries + */ + insecure?: boolean; +} + +export interface Push { + /** + * Push job identifier + */ + id: string; + + created_at: string; + + /** + * Cached manifest digest being pushed + */ + digest: string; + + /** + * Hypeman image name (normalized ref) + */ + image: string; + + status: PushStatus; + + /** + * Remote reference the image is pushed to + */ + target: string; + + /** + * Total compressed layer bytes pushed + */ + bytes?: number; + + completed_at?: string | null; + + /** + * Error message + */ + error?: string | null; + + /** + * Number of layers pushed + */ + layers?: number; + + /** + * Position in the push queue + */ + queue_position?: number | null; +} + +/** + * Registry credentials borrowed for this push only. When omitted, the server's own + * registry credentials are used. + */ +export interface PushCredentials { + /** + * Registry password or access token + */ + password?: string; + + /** + * Bearer token for an Authorization header + */ + registry_token?: string; + + /** + * Registry username + */ + username?: string; +} + +export type PushStatus = 'queued' | 'pushing' | 'pushed' | 'failed'; + +export type PushListResponse = Array; + +export interface PushCreateParams { + /** + * Hypeman image name to push (tag or digest form) + */ + image: string; + + /** + * Full remote reference to push to + */ + target: string; + + /** + * Registry credentials borrowed for this push only. When omitted, the server's own + * registry credentials are used. + */ + credentials?: PushCredentials; + + /** + * Allow pushing to plain-HTTP registries + */ + insecure?: boolean; +} + +export declare namespace Pushes { + export { + type CreatePushRequest as CreatePushRequest, + type Push as Push, + type PushCredentials as PushCredentials, + type PushStatus as PushStatus, + type PushListResponse as PushListResponse, + type PushCreateParams as PushCreateParams, + }; +} diff --git a/src/resources/resources.ts b/src/resources/resources.ts index c6eaee8..7b407b2 100644 --- a/src/resources/resources.ts +++ b/src/resources/resources.ts @@ -117,7 +117,7 @@ export interface MemoryReclaimAction { assigned_memory_bytes: number; - hypervisor: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + hypervisor: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; instance_id: string; diff --git a/src/resources/snapshots.ts b/src/resources/snapshots.ts index 8bf1b45..f458830 100644 --- a/src/resources/snapshots.ts +++ b/src/resources/snapshots.ts @@ -94,7 +94,7 @@ export interface Snapshot { /** * Source instance hypervisor at snapshot creation time */ - source_hypervisor: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + source_hypervisor: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; /** * Source instance ID at snapshot creation time @@ -179,7 +179,7 @@ export interface SnapshotForkParams { * Optional hypervisor override. Allowed only when forking from a Stopped snapshot. * Standby snapshots must fork with their original hypervisor. */ - target_hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'vz'; + target_hypervisor?: 'cloud-hypervisor' | 'firecracker' | 'qemu' | 'qemu-microvm' | 'vz'; /** * Optional final state for the forked instance. Defaults by snapshot kind: diff --git a/src/version.ts b/src/version.ts index 44c3338..30c2817 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.5.1'; // x-release-please-version +export const VERSION = '0.6.0'; // x-release-please-version diff --git a/tests/api-resources/ingresses.test.ts b/tests/api-resources/ingresses.test.ts index 9f53e27..0add894 100644 --- a/tests/api-resources/ingresses.test.ts +++ b/tests/api-resources/ingresses.test.ts @@ -37,6 +37,10 @@ describe('resource ingresses', () => { match: { hostname: '{instance}.example.com', port: 8080 }, target: { instance: '{instance}', port: 8080 }, redirect_http: true, + request_header_auth: { + header: 'X-Ingress-Verification', + value: '0123456789abcdef0123456789abcdef', + }, tls: true, }, ], diff --git a/tests/api-resources/pushes.test.ts b/tests/api-resources/pushes.test.ts new file mode 100644 index 0000000..5df3265 --- /dev/null +++ b/tests/api-resources/pushes.test.ts @@ -0,0 +1,63 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Hypeman from '@onkernel/hypeman'; + +const client = new Hypeman({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource pushes', () => { + // Mock server tests are disabled + test.skip('create: only required params', async () => { + const responsePromise = client.pushes.create({ + image: 'docker.io/library/alpine:latest', + target: '123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:v1', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('create: required and optional params', async () => { + const response = await client.pushes.create({ + image: 'docker.io/library/alpine:latest', + target: '123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:v1', + credentials: { + password: 'password', + registry_token: 'registry_token', + username: 'username', + }, + insecure: true, + }); + }); + + // Mock server tests are disabled + test.skip('list', async () => { + const responsePromise = client.pushes.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('get', async () => { + const responsePromise = client.pushes.get('id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +});