diff --git a/README.md b/README.md index 9db4c68..210433f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,14 @@ [![npm downloads][npmx-downloads-src]][npmx-href] [![Unit Test][unit-test-src]][unit-test-href] -placeholder +`flowpack` is a lockfile-first GitHub Actions workflow packer. It lets you +author workflows in `.github/workflows/src/`, lock every remote workflow/action +dependency in `.github/workflow.lock.yml`, and generate pinned workflows in +`.github/workflows/`. + +It currently supports inlining composite actions and safely transformable +reusable workflows. JavaScript and Docker actions are pinned as external +dependencies instead of being bundled. ## Install @@ -12,6 +19,132 @@ placeholder npm i flowpack ``` +## Usage + +Put authored workflows under `.github/workflows/src/`: + +```yaml +# .github/workflows/src/ci.yml +name: CI + +on: + push: + +jobs: + test: + uses: owner/repo/.github/workflows/test.yml@main +``` + +Then run: + +```bash +npx flowpack +``` + +`flowpack` defaults to `flowpack pack`. It writes: + +- `.github/workflow.lock.yml` +- `.github/workflows/ci.yml` + +Generated workflows are safe to commit. Existing lockfile SHAs are reused until +you explicitly run `flowpack update`. + +## Commands + +```bash +flowpack pack +``` + +Scan source workflows, resolve missing dependencies, update the lockfile, and +write generated workflows. + +```bash +flowpack scan +``` + +Update the lockfile graph shape only. This adds newly discovered dependencies +and removes unreachable ones without refreshing existing SHAs. + +```bash +flowpack update [package] +``` + +Refresh all locked dependencies, or only the selected package. By default this +also packs workflows. Use `--lockfile-only` to update only +`.github/workflow.lock.yml`. + +```bash +flowpack verify +``` + +Check that generated workflows are current and contain no unsupported unpinned +remote references. + +```bash +flowpack tree +flowpack why +flowpack diff +flowpack diff --json +``` + +Inspect the lockfile dependency tree, explain why a package is present, or +compare the current lockfile with `HEAD`. + +## Configuration + +`flowpack.yml` is optional. Without it, `flowpack` discovers +`.github/workflows/src/*.yml` and `.github/workflows/src/*.yaml`, then writes +matching generated workflows to `.github/workflows/*.yml`. + +Use explicit entries when you need custom paths: + +```yaml +$schema: ./flowpack.schema.json + +entries: + - source: .github/workflows/src/ci.yml + output: .github/workflows/ci.yml +``` + +Use `external` to pin a workflow or action without bundling it: + +```yaml +external: + - actions/checkout + - owner/repo/path +``` + +The same configuration can be supplied through CLI flags: + +```bash +flowpack pack \ + --entry .github/workflows/src/ci.yml:.github/workflows/ci.yml \ + --external actions/checkout +``` + +## Packing Rules + +Composite actions are recursively inlined when `runs.using` is `composite`. +Inputs are substituted from caller `with` values or action defaults. Missing +required inputs fail closed. + +Reusable workflows are inlined only when they use `workflow_call` and can be +transformed into local jobs deterministically. Unsupported cases, unresolved +refs, unsafe reusable workflows, and leftover remote `uses` fail closed. + +JavaScript actions, Docker actions, and `docker://` references are not bundled +yet. They are pinned to locked SHAs as external dependencies. + +## API + +```ts +import { diff, pack, scan, tree, update, verify, why } from 'flowpack' + +await pack() +await update({ packageName: 'owner/repo', lockfileOnly: true }) +await verify() +``` + ## Sponsors

diff --git a/flowpack.schema.json b/flowpack.schema.json index 01b70cd..557ff5a 100644 --- a/flowpack.schema.json +++ b/flowpack.schema.json @@ -34,7 +34,7 @@ } }, "external": { - "description": "GitHub actions or reusable workflows to pin in the lockfile but not bundle. Selectors may be owner/repo, owner/repo/path, or github:owner/repo//path.", + "description": "GitHub actions or reusable workflows to pin in the lockfile but not bundle. Selectors may be owner/repo, owner/repo/path, or github:owner/repo/path.", "type": "array", "items": { "type": "string", @@ -43,7 +43,7 @@ "examples": [ "actions/checkout", "owner/repo/path", - "github:owner/repo//path" + "github:owner/repo/path" ] } } diff --git a/package.json b/package.json index d368376..eeba3da 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "type": "module", "version": "0.0.0", "packageManager": "pnpm@11.1.3", - "description": "placeholder", + "description": "Lockfile-first GitHub Actions workflow packer", "author": "Kevin Deng ", "license": "MIT", "funding": "https://github.com/sponsors/sxzz", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 370188c..d6ebd29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + fflate: 0.8.2 + importers: .: @@ -1425,8 +1428,8 @@ packages: picomatch: optional: true - fflate@0.8.3: - resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} @@ -2304,7 +2307,7 @@ snapshots: '@andrewbranch/untar.js': 1.0.3 '@loaderkit/resolve': 1.0.6 cjs-module-lexer: 1.4.3 - fflate: 0.8.3 + fflate: 0.8.2 lru-cache: 11.4.0 semver: 7.8.0 typescript: 5.6.1-rc @@ -3528,7 +3531,7 @@ snapshots: optionalDependencies: picomatch: 4.0.4 - fflate@0.8.3: {} + fflate@0.8.2: {} file-entry-cache@8.0.0: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d0cffdc..e066154 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,6 @@ -packages: [] +overrides: + fflate: 0.8.2 trustPolicy: no-downgrade trustPolicyIgnoreAfter: 604800 # 7 days +