Feel free to add your project or company here to join the pkg.pr.new family :)
You can also join our discord server [here](https://discord.gg/stackblitz), so we all have fun together!
## Setup
First [install the GitHub Application](https://github.com/apps/pkg-pr-new).
> [!IMPORTANT]
> Make sure it's installed on the repository before trying to publish a package. To read about the permissions the app needs, check [#305](https://github.com/stackblitz-labs/pkg.pr.new/issues/305).
After installing on your repository, run `pkg-pr-new` from your lockfile in workflows (for example with `pnpm exec pkg-pr-new publish`) to get continuous releases.
```sh
npm install --save-dev pkg-pr-new
```
For workspaces and monorepos:
```sh
pnpm exec pkg-pr-new publish './packages/A' './packages/B' # or `pnpm exec pkg-pr-new publish './packages/*'`
```
You can also pass **prebuilt tarballs** (`.tgz` or `.tar.gz`) directly, which is handy when your build pipeline already produces tarballs in a custom way:
```sh
pnpm exec pkg-pr-new publish './artifacts/*.tgz'
```
> [!NOTE]
> Prebuilt tarballs are uploaded **as-is**: pkg.pr.new will not repack them. If one tarball references another tarball being published in the same call, pkg.pr.new will print a warning and that reference will not be rewritten to a pkg.pr.new URL. Repack with the resolved version yourself if you need cross-package linking.
> [!CAUTION]
> In CI environments, avoid `npx`, `pnpm dlx`, `yarn dlx`, and `bunx` for this step. Install `pkg-pr-new` as a dependency and execute it from the lockfile (`npm exec`, `pnpm exec`, `yarn`, or `bun run`).
> [!IMPORTANT]
> Make sure the pkg-pr-new command runs only once in a defined workflow (that's part of how it avoids spam)! So instead of multiple times running pkg-pr-new for each workspace package, the command should be run one time for all the desired packages using the pattern above.
For templates (experimental):
> [!NOTE]
> With templates, pkg.pr.new will generate Stackblitz instances for the given directories with the new built packages.
```sh
pnpm exec pkg-pr-new publish './packages/A' --template './examples/*'
```
By default, pkg.pr.new will generate a template called "default" which includes each built package in the dependencies. This can be disabled with `--no-template`.
Compact URLs are the default (and will fall back to long form if npm metadata is unavailable). To force long-form URLs, use `--no-compact`:
```sh
pnpm exec pkg-pr-new publish --no-compact './packages/A' './packages/B'
```
> Compact URLs rely on your package being published on npm with a valid `repository` field in `package.json`. See [this](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#repository). pkg.pr.new is case sensitive, if the GitHub owner is `PuruVJ`, the package.json `repository` field should not have `puruvj`.
With default compact URLs:
```sh
npm i https://pkg.pr.new/tinybench@a832a55
```
With `--no-compact` or if npm metadata is unavailable:
```sh
npm i https://pkg.pr.new/tinylibs/tinybench/tinybench@a832a55
```
For CLI applications you might want to show `npx` instead of `npm i` for the preview command. This can be accomplished with the `--bin` flag:
```sh
pnpm exec pkg-pr-new publish --bin
```
With `--bin`:
```sh
npx https://pkg.pr.new/pkg-pr-new@a832a55
```
Without `--bin`:
```sh
npm i https://pkg.pr.new/pkg-pr-new@a832a55
```
You can control publishing comments with `--comment`:
```sh
pnpm exec pkg-pr-new publish --comment=update # default
```
Using `--comment=update`, pkg.pr.new would generate one initial comment and then edit it in the following commits.
With `--comment=create`, each commit would generate a comment for itself, useful for triggering workflows, like workflow execution using maintainer comments.
And `--comment=off` would turn off comments for maintainers who prefer minimal pull requests.
> `--commentWithSha` specifies whether to replace the PR number with the commit SHA in the generated comments.
With `--commentWithSha`:
```sh
pnpm exec pkg-pr-new publish --commentWithSha
```
Generated comments use commit SHA URLs:
```sh
npm i https://pkg.pr.new/tinybench@a832a55
```
Without `--commentWithSha`:
```sh
pnpm exec pkg-pr-new publish
```
Generated comments use PR number URLs:
```sh
npm i https://pkg.pr.new/tinybench@123
```
> `--commentWithDev` specify whether the generated link includes the `-D` parameter.
With `--commentWithDev`:
```sh
npm i https://pkg.pr.new/tinybench@123 -D
```
Without `--commentWithDev`:
```sh
npm i https://pkg.pr.new/tinybench@123
```
To customize which package manager is reflected in the comments, use the `--packageManager=XYZ` flag. XYZ can be one of the following: npm (default), pnpm, yarn, or bun. Multiple valid values ββcan also be configured at the same time, such as `--packageManager=ABC,XYZ`.
For repositories with many packages, comments might get too long. In that case, you can use `--only-templates` to only show templates.
pkg.pr.new uses `npm pack --json` under the hood, in case you face issues, you can also use the `--pnpm`, `--yarn`, or `--bun` flag so it starts using `pnpm pack`, `yarn pack`, or `bun pm pack`. This is not necessary in most cases.
pkg.pr.new is not available in your local environment and it only works in workflows.
### Examples
#### Release each commit and pull request:
```yml
name: Publish Any Commit
on: [push, pull_request]
permissions: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- run: pnpm exec pkg-pr-new publish --commentWithSha
```
#### Release approved pull requests only:
```yml
name: Publish Approved Pull Requests
on:
pull_request_review:
types: [submitted]
permissions: {}
jobs:
check:
# First, trigger a permissions check on the user approving the pull request.
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
outputs:
has-permissions: ${{ steps.checkPermissions.outputs.require-result }}
steps:
- name: Check permissions
id: checkPermissions
uses: actions-cool/check-user-permission@v2
with:
# In this example, the approver must have the write access
# to the repository to trigger the package preview.
require: "write"
publish:
needs: check
# Publish the preview package only if the permissions check passed.
if: needs.check.outputs.has-permissions == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- run: pnpm exec pkg-pr-new publish --commentWithSha
```
> Releasing approved pull requests is the recommended way of having continuous releases. This ensures users always install approved and safe packages.
> [!TIP]
> For any in-repo branch not yet opened as a pull request, if pkg.pr.new has already run on it, a `@branch-name` tag will link to the latest commit. Example: http://pkg.pr.new/vite@main
#### Avoid publishing on tags
```yml
on:
pull_request:
push:
branches:
- "**"
tags:
- "!**"
```
As noted in [#140](https://github.com/stackblitz-labs/pkg.pr.new/issues/140), workflows run on tags too, that's not an issue at all, but in case users would like to avoid duplicate publishes.
#### Run E2E test using outputs
After `pkg-pr-new publish` runs successfully, some outputs are available.
- `sha`: The short SHA used. (E.g. `a832a55`)
- `urls`: Space-separated URLs of published packages.
- `packages`: Space-separated, Yarn-compatible package locators of published packages.
This is useful for using published packages in other subsequent jobs immediately after publishing. (E.g. E2E tests)
```yml
name: Publish and Test Packages
on: [push, pull_request]
permissions: {}
jobs:
publish:
runs-on: ubuntu-latest
outputs:
sha: ${{ steps.publish.outputs.sha }}
urls: ${{ steps.publish.outputs.urls }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- id: publish
run: pnpm exec pkg-pr-new publish --commentWithSha
e2e-test:
runs-on: ubuntu-latest
needs: publish
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
repository: user/my-package-e2e
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: pnpm install
- name: Install published package
run: pnpm add ${{ needs.publish.outputs.urls }}
- name: Run e2e test cases
run: # ...
```
## Custom GitHub Messages and Comments
For advanced use cases where you want more control over the messages posted by pkg.pr.new, you can use the `--json` option in combination with `--comment=off`. This allows you to generate metadata about the publish operation without creating a default comment, which you can then use to create custom comments via the GitHub Actions API.
### Steps:
1. Use pkg.pr.new with the `--json` and `--comment=off` options in your workflow:
```yml
- name: Publish packages
run: pnpm exec pkg-pr-new publish --json output.json --comment=off
```
2. Add a custom step in your workflow to process the JSON output and create a custom comment:
```yml
- name: Post or update comment
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const output = JSON.parse(fs.readFileSync('output.json', 'utf8'));
const packages = output.packages
.map((p) => `- ${p.name}: ${p.url}`)
.join('\n');
const templates = output.templates
.map((t) => `- [${t.name}](${t.url})`)
.join('\n');
const sha =
context.event_name === 'pull_request'
? context.payload.pull_request.head.sha
: context.payload.after;
const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`;
const body = `## Custom Publish Message
### Published Packages:
${packages}
### Templates:
${templates}
[View Commit](${commitUrl})`;
const botCommentIdentifier = '## Custom Publish Message';
async function findBotComment(issueNumber) {
if (!issueNumber) return null;
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
return comments.data.find((comment) =>
comment.body.includes(botCommentIdentifier)
);
}
async function createOrUpdateComment(issueNumber) {
if (!issueNumber) {
console.log('No issue number provided. Cannot post or update comment.');
return;
}
const existingComment = await findBotComment(issueNumber);
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: body,
});
} else {
await github.rest.issues.createComment({
issue_number: issueNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
}
}
async function logPublishInfo() {
console.log('\n' + '='.repeat(50));
console.log('Publish Information');
console.log('='.repeat(50));
console.log('\nPublished Packages:');
console.log(packages);
console.log('\nTemplates:');
console.log(templates);
console.log(`\nCommit URL: ${commitUrl}`);
console.log('\n' + '='.repeat(50));
}
if (context.eventName === 'pull_request') {
if (context.issue.number) {
await createOrUpdateComment(context.issue.number);
}
} else if (context.eventName === 'push') {
const pullRequests = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.ref.replace(
'refs/heads/',
''
)}`,
});
if (pullRequests.data.length > 0) {
await createOrUpdateComment(pullRequests.data[0].number);
} else {
console.log(
'No open pull request found for this push. Logging publish information to console:'
);
await logPublishInfo();
}
}
```
This custom script does the following:
- For pull requests: It creates or updates a comment with the publish information.
- For pushes with an associated open PR: It adds or updates a comment on that PR.
- For pushes without an open PR (e.g., direct pushes to main): It logs the publish information to the GitHub Actions console.
This is a sample recipe that users can adapt with `--json` and `--comment=off` to create custom comments.
This custom approach gives you full control over how pkg.pr.new communicates its results.
---
Publishing is only available in workflows and it supports any workflow trigger event, more information [here](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#about-events-that-trigger-workflows).