Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ An explicit token always wins over the OIDC exchange.

## How it works

Each run has three phases: install, build, and deploy. Your workflow owns checkout and the toolchain. The action runs your install and build commands exactly as configured, and it never inspects your repository to decide how to build. The deploy phase hands your built app to the [Prisma Composer](https://github.com/prisma/composer) CLI, running it under Bun. Bun must be on the runner PATH — add `oven-sh/setup-bun@v2` before this action. The generated Prisma deploy workflow includes that step automatically.
Each run has three phases: install, build, and deploy. Your workflow owns checkout and the toolchain. The action runs your install and build commands exactly as configured, and it never inspects your repository to decide how to build. A repository with no build script — one that runs its source directly — sets `build-command: none` to skip the build phase. The deploy phase hands your built app to the [Prisma Composer](https://github.com/prisma/composer) CLI, running it under Bun. Bun must be on the runner PATH — add `oven-sh/setup-bun@v2` before this action. The generated Prisma deploy workflow includes that step automatically.

Deploy targets follow your branches:

Expand All @@ -88,7 +88,7 @@ The credential resolves in order: an explicit `PRISMA_SERVICE_TOKEN` from the en

| Input | Default | Description |
| --- | --- | --- |
| `build-command` | `npm run build` | Your build command, run verbatim. It runs in both modes, because destroy evaluates the built app to know what to remove. |
| `build-command` | `npm run build` | Your build command, run verbatim. It runs in both modes, because destroy evaluates the built app to know what to remove. The exact value `none` skips the build phase in both modes, for repositories with no build script; an empty value keeps the default. |
| `install-command` | auto | Detected from the lockfile: `npm ci` for `package-lock.json`, `bun install --frozen-lockfile` for a bun lockfile. Set this to override. pnpm and yarn are not supported yet. |
| `module` | `module.ts` | Path to your app's Composer module. |
| `mode` | `deploy` | `deploy` or `destroy`. |
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Deploy to Prisma Cloud
description: Build and deploy your app to Prisma Cloud from GitHub Actions
inputs:
build-command:
description: Your build command, run verbatim in both modes
description: Your build command, run verbatim in both modes; the exact value "none" skips the build phase
default: npm run build
install-command:
description: Empty auto-detects from the lockfile (npm ci or bun install --frozen-lockfile)
Expand Down
14 changes: 14 additions & 0 deletions build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Returns the build command to run, or null to skip the build phase.
*
* Only the exact value "none" skips — for repos with no build script whose
* source runs directly. An empty input falls back to the default, so a blank
* value or a typo can never silently skip a build.
*
* @param {string} rawInput - The trimmed build-command input ("" when unset).
* @returns {string | null}
*/
export function selectBuildCommand(rawInput) {
if (rawInput === "none") return null;
return rawInput || "npm run build";
}
13 changes: 11 additions & 2 deletions main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { spawnSync } from "node:child_process";
import { appendFileSync, existsSync, readFileSync, writeSync } from "node:fs";
import { join, resolve } from "node:path";
import { selectBuildCommand } from "./build.mjs";
import { selectComposerCommand } from "./composer.mjs";
import { resolveCredential } from "./credentials.mjs";
import { deployedUrlFromOutput } from "./deployment.mjs";
Expand Down Expand Up @@ -230,8 +231,16 @@ await runPhase("install", installCommand);
// same stack program as deploy, which packages the built artifacts — so the
// app must be built first" (its error text on 0.6.0). We wanted destroy to
// skip the build so teardown never depends on the default branch's build
// health; composer does not allow that today.
await runPhase("build", input("build-command") || "npm run build");
// health; composer does not allow that today. `build-command: none` is
// different: the app has no build step at all, so both modes skip the phase.
const buildCommand = selectBuildCommand(input("build-command"));
if (buildCommand === null) {
// Install already reported the server-side "build" phase (mapPhase sends
// install as "build"), so the skip needs no report update of its own.
log("build: skipped (build-command: none)");
} else {
await runPhase("build", buildCommand);
}

// The stage reaches the argv array straight from the environment; it is
// never interpolated into a shell string.
Expand Down
23 changes: 23 additions & 0 deletions tests/build.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { selectBuildCommand } from "../build.mjs";

test('the exact value "none" skips the build', () => {
assert.equal(selectBuildCommand("none"), null);
});

test("an empty input falls back to the default build command", () => {
assert.equal(selectBuildCommand(""), "npm run build");
});

test("any other command runs verbatim", () => {
assert.equal(selectBuildCommand("bun run build"), "bun run build");
});

test('a near-miss like "None" runs verbatim instead of skipping', () => {
assert.equal(selectBuildCommand("None"), "None");
});

test('a command containing "none" runs verbatim', () => {
assert.equal(selectBuildCommand("npm run none"), "npm run none");
});
Loading