mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 08:03:30 +01:00
ci: implement workflow to publish dev versions (#11120)
* ci: implement workflow to publish dev versions * ci: refactor into the other dev job * fix: use dev tag * chore: clarify * fix: always use actions from main * fix: conditionally * chore: don't ask for meaningless perm
This commit is contained in:
committed by
GitHub
parent
fcf7f27fd7
commit
0c2975e3fd
57
.github/workflows/publish-dev.yml
vendored
57
.github/workflows/publish-dev.yml
vendored
@@ -4,6 +4,14 @@ on:
|
||||
- cron: '0 */12 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pull:
|
||||
description: 'The pull number to check out'
|
||||
required: false
|
||||
default: 'main'
|
||||
tag:
|
||||
description: 'The tag to use, generally a feature name'
|
||||
required: false
|
||||
type: string
|
||||
dry_run:
|
||||
description: 'Perform a dry run that skips publishing and outputs logs indicating what would have happened'
|
||||
type: boolean
|
||||
@@ -19,10 +27,27 @@ jobs:
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v2
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.DISCORDJS_APP_ID }}
|
||||
private-key: ${{ secrets.DISCORDJS_APP_KEY_RELEASE }}
|
||||
|
||||
- name: Decide ref
|
||||
id: ref
|
||||
run: |
|
||||
if [ -n "${{ github.event.inputs.pull }}" ]; then
|
||||
echo "ref=refs/pull/${{ github.event.inputs.pull }}/head" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ref=refs/heads/main" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
|
||||
- name: Install Node.js v22
|
||||
uses: actions/setup-node@v5
|
||||
@@ -37,12 +62,42 @@ jobs:
|
||||
- name: Build dependencies
|
||||
run: pnpm run build
|
||||
|
||||
- name: Publish packages
|
||||
- name: Checkout main repository (non-main ref)
|
||||
if: ${{ steps.ref.outputs.ref != 'refs/heads/main' }}
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
path: 'main'
|
||||
|
||||
- name: Install action deps (non-main ref)
|
||||
if: ${{ steps.ref.outputs.ref != 'refs/heads/main' }}
|
||||
shell: bash
|
||||
working-directory: ./main
|
||||
env:
|
||||
COREPACK_ENABLE_STRICT: 0
|
||||
run: |
|
||||
pnpm self-update 10
|
||||
pnpm install --filter @discordjs/actions --frozen-lockfile --prefer-offline --loglevel error
|
||||
|
||||
- name: Publish packages (non-main ref)
|
||||
if: ${{ steps.ref.outputs.ref != 'refs/heads/main' }}
|
||||
uses: ./main/packages/actions/src/releasePackages
|
||||
with:
|
||||
exclude: '@discordjs/docgen'
|
||||
dry: ${{ inputs.dry_run }}
|
||||
dev: true
|
||||
tag: ${{ inputs.tag || 'dev' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish packages (main ref)
|
||||
if: ${{ steps.ref.outputs.ref == 'refs/heads/main' }}
|
||||
uses: ./packages/actions/src/releasePackages
|
||||
with:
|
||||
exclude: '@discordjs/docgen'
|
||||
dry: ${{ inputs.dry_run }}
|
||||
dev: true
|
||||
tag: ${{ inputs.tag || 'dev' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -11,6 +11,8 @@ inputs:
|
||||
description: 'The published name of a single package to release'
|
||||
exclude:
|
||||
description: 'Comma separated list of packages to exclude from release (if not depended upon)'
|
||||
tag:
|
||||
description: 'The tag to use, generally a feature name'
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -22,3 +24,4 @@ runs:
|
||||
INPUT_DRY: ${{ inputs.dry }}
|
||||
INPUT_PACKAGE: ${{ inputs.package }}
|
||||
INPUT_EXCLUDE: ${{ inputs.exclude }}
|
||||
INPUT_TAG: ${{ inputs.tag }}
|
||||
|
||||
@@ -26,9 +26,9 @@ export interface ReleaseEntry {
|
||||
version: string;
|
||||
}
|
||||
|
||||
async function fetchDevVersion(pkg: string) {
|
||||
async function fetchDevVersion(pkg: string, tag: string) {
|
||||
try {
|
||||
const res = await fetch(`https://registry.npmjs.org/${pkg}/dev`);
|
||||
const res = await fetch(`https://registry.npmjs.org/${pkg}/${tag}`);
|
||||
if (!res.ok) return null;
|
||||
const packument = (await res.json()) as PackumentVersion;
|
||||
return packument.version;
|
||||
@@ -37,7 +37,7 @@ async function fetchDevVersion(pkg: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getReleaseEntries(dev: boolean, dry: boolean) {
|
||||
async function getReleaseEntries(dry: boolean, devTag?: string) {
|
||||
const releaseEntries: ReleaseEntry[] = [];
|
||||
const packageList: pnpmTree[] =
|
||||
await $`pnpm list --recursive --only-projects --filter {packages/\*} --prod --json`.json();
|
||||
@@ -57,8 +57,8 @@ async function getReleaseEntries(dev: boolean, dry: boolean) {
|
||||
version: pkg.version,
|
||||
};
|
||||
|
||||
if (dev) {
|
||||
const devVersion = await fetchDevVersion(pkg.name);
|
||||
if (devTag) {
|
||||
const devVersion = await fetchDevVersion(pkg.name, devTag);
|
||||
if (devVersion?.endsWith(commitHash)) {
|
||||
// Write the currently released dev version so when pnpm publish runs on dependents they depend on the dev versions
|
||||
if (dry) {
|
||||
@@ -72,9 +72,9 @@ async function getReleaseEntries(dev: boolean, dry: boolean) {
|
||||
release.version = devVersion;
|
||||
} else if (dry) {
|
||||
info(`[DRY] Bumping ${pkg.name} via git-cliff.`);
|
||||
release.version = `${pkg.version}.DRY-dev.${timestamp}-${commitHash}`;
|
||||
release.version = `${pkg.version}.DRY-${devTag}.${timestamp}-${commitHash}`;
|
||||
} else {
|
||||
await $`pnpm --filter=${pkg.name} run release --preid "dev.${timestamp}-${commitHash}" --skip-changelog`;
|
||||
await $`pnpm --filter=${pkg.name} run release --preid "${devTag}.${timestamp}-${commitHash}" --skip-changelog`;
|
||||
// Read again instead of parsing the output to be sure we're matching when checking against npm
|
||||
const pkgJson = (await file(`${pkg.path}/package.json`).json()) as PackageJSON;
|
||||
release.version = pkgJson.version;
|
||||
@@ -129,8 +129,8 @@ async function getReleaseEntries(dev: boolean, dry: boolean) {
|
||||
return releaseEntries;
|
||||
}
|
||||
|
||||
export async function generateReleaseTree(dev: boolean, dry: boolean, packageName?: string, exclude?: string[]) {
|
||||
let releaseEntries = await getReleaseEntries(dev, dry);
|
||||
export async function generateReleaseTree(dry: boolean, devTag?: string, packageName?: string, exclude?: string[]) {
|
||||
let releaseEntries = await getReleaseEntries(dry, devTag);
|
||||
// Try to early return if the package doesn't have deps
|
||||
if (packageName && packageName !== 'all') {
|
||||
const releaseEntry = releaseEntries.find((entry) => entry.name === packageName);
|
||||
|
||||
@@ -30,15 +30,29 @@ program
|
||||
)
|
||||
.option('--dry', 'skips actual publishing and outputs logs instead', dryInput)
|
||||
.option('--dev', 'publishes development versions and skips tagging / github releases', devInput)
|
||||
.option('--tag <tag>', 'tag to use for dev releases (defaults to "dev")', getInput('tag'))
|
||||
.parse();
|
||||
|
||||
const { exclude, dry, dev } = program.opts<{ dev: boolean; dry: boolean; exclude: string[] }>();
|
||||
const [packageName] = program.processedArgs as [string];
|
||||
const {
|
||||
exclude,
|
||||
dry,
|
||||
dev,
|
||||
tag: inputTag,
|
||||
} = program.opts<{ dev: boolean; dry: boolean; exclude: string[]; tag: string }>();
|
||||
|
||||
// All this because getInput('tag') will return empty string when not set :P
|
||||
if (!dev && inputTag.length) {
|
||||
throw new Error('The --tag option can only be used with --dev');
|
||||
}
|
||||
|
||||
const tag = inputTag.length ? inputTag : dev ? 'dev' : undefined;
|
||||
|
||||
const [packageName] = program.processedArgs as [string];
|
||||
const tree = await generateReleaseTree(dry, tag, packageName, exclude);
|
||||
|
||||
const tree = await generateReleaseTree(dev, dry, packageName, exclude);
|
||||
for (const branch of tree) {
|
||||
startGroup(`Releasing ${branch.map((entry) => `${entry.name}@${entry.version}`).join(', ')}`);
|
||||
await Promise.all(branch.map(async (release) => releasePackage(release, dev, dry)));
|
||||
await Promise.all(branch.map(async (release) => releasePackage(release, dry, tag)));
|
||||
endGroup();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ async function gitTagAndRelease(release: ReleaseEntry, dry: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: boolean, doGitRelease = !dev) {
|
||||
export async function releasePackage(release: ReleaseEntry, dry: boolean, devTag?: string, doGitRelease = !devTag) {
|
||||
// Sanity check against the registry first
|
||||
if (await checkRegistry(release)) {
|
||||
info(`${release.name}@${release.version} already published, skipping.`);
|
||||
@@ -51,11 +51,11 @@ export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: b
|
||||
if (dry) {
|
||||
info(`[DRY] Releasing ${release.name}@${release.version}`);
|
||||
} else {
|
||||
await $`pnpm --filter=${release.name} publish --provenance --no-git-checks ${dev ? '--tag=dev' : ''}`;
|
||||
await $`pnpm --filter=${release.name} publish --provenance --no-git-checks ${devTag ? `--tag=${devTag}` : ''}`;
|
||||
}
|
||||
|
||||
// && !dev just to be sure
|
||||
if (doGitRelease && !dev) await gitTagAndRelease(release, dry);
|
||||
// && !devTag just to be sure
|
||||
if (doGitRelease && !devTag) await gitTagAndRelease(release, dry);
|
||||
|
||||
if (dry) return;
|
||||
|
||||
@@ -77,9 +77,9 @@ export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: b
|
||||
}, 15_000);
|
||||
});
|
||||
|
||||
if (dev) {
|
||||
if (devTag) {
|
||||
// Send and forget, deprecations are less important than releasing other dev versions and can be done manually
|
||||
void $`pnpm exec npm-deprecate --name "*dev*" --message "This version is deprecated. Please use a newer version." --package ${release.name}`
|
||||
void $`pnpm exec npm-deprecate --name "*${devTag}*" --message "This version is deprecated. Please use a newer version." --package ${release.name}`
|
||||
.nothrow()
|
||||
// eslint-disable-next-line promise/prefer-await-to-then
|
||||
.then(() => {});
|
||||
@@ -90,6 +90,6 @@ export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: b
|
||||
await $`pnpm --filter=create-discord-bot run rename-to-app`;
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
release.name = 'create-discord-app';
|
||||
await releasePackage(release, dev, dry, false);
|
||||
await releasePackage(release, dry, devTag, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user