mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +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 * * *'
|
- cron: '0 */12 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
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:
|
dry_run:
|
||||||
description: 'Perform a dry run that skips publishing and outputs logs indicating what would have happened'
|
description: 'Perform a dry run that skips publishing and outputs logs indicating what would have happened'
|
||||||
type: boolean
|
type: boolean
|
||||||
@@ -19,10 +27,27 @@ jobs:
|
|||||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||||
if: github.repository_owner == 'discordjs'
|
if: github.repository_owner == 'discordjs'
|
||||||
steps:
|
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
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
token: ${{ steps.app-token.outputs.token }}
|
||||||
|
ref: ${{ steps.ref.outputs.ref }}
|
||||||
|
|
||||||
- name: Install Node.js v22
|
- name: Install Node.js v22
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
@@ -37,12 +62,42 @@ jobs:
|
|||||||
- name: Build dependencies
|
- name: Build dependencies
|
||||||
run: pnpm run build
|
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
|
uses: ./packages/actions/src/releasePackages
|
||||||
with:
|
with:
|
||||||
exclude: '@discordjs/docgen'
|
exclude: '@discordjs/docgen'
|
||||||
dry: ${{ inputs.dry_run }}
|
dry: ${{ inputs.dry_run }}
|
||||||
dev: true
|
dev: true
|
||||||
|
tag: ${{ inputs.tag || 'dev' }}
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ inputs:
|
|||||||
description: 'The published name of a single package to release'
|
description: 'The published name of a single package to release'
|
||||||
exclude:
|
exclude:
|
||||||
description: 'Comma separated list of packages to exclude from release (if not depended upon)'
|
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:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
@@ -22,3 +24,4 @@ runs:
|
|||||||
INPUT_DRY: ${{ inputs.dry }}
|
INPUT_DRY: ${{ inputs.dry }}
|
||||||
INPUT_PACKAGE: ${{ inputs.package }}
|
INPUT_PACKAGE: ${{ inputs.package }}
|
||||||
INPUT_EXCLUDE: ${{ inputs.exclude }}
|
INPUT_EXCLUDE: ${{ inputs.exclude }}
|
||||||
|
INPUT_TAG: ${{ inputs.tag }}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ export interface ReleaseEntry {
|
|||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchDevVersion(pkg: string) {
|
async function fetchDevVersion(pkg: string, tag: string) {
|
||||||
try {
|
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;
|
if (!res.ok) return null;
|
||||||
const packument = (await res.json()) as PackumentVersion;
|
const packument = (await res.json()) as PackumentVersion;
|
||||||
return packument.version;
|
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 releaseEntries: ReleaseEntry[] = [];
|
||||||
const packageList: pnpmTree[] =
|
const packageList: pnpmTree[] =
|
||||||
await $`pnpm list --recursive --only-projects --filter {packages/\*} --prod --json`.json();
|
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,
|
version: pkg.version,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dev) {
|
if (devTag) {
|
||||||
const devVersion = await fetchDevVersion(pkg.name);
|
const devVersion = await fetchDevVersion(pkg.name, devTag);
|
||||||
if (devVersion?.endsWith(commitHash)) {
|
if (devVersion?.endsWith(commitHash)) {
|
||||||
// Write the currently released dev version so when pnpm publish runs on dependents they depend on the dev versions
|
// Write the currently released dev version so when pnpm publish runs on dependents they depend on the dev versions
|
||||||
if (dry) {
|
if (dry) {
|
||||||
@@ -72,9 +72,9 @@ async function getReleaseEntries(dev: boolean, dry: boolean) {
|
|||||||
release.version = devVersion;
|
release.version = devVersion;
|
||||||
} else if (dry) {
|
} else if (dry) {
|
||||||
info(`[DRY] Bumping ${pkg.name} via git-cliff.`);
|
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 {
|
} 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
|
// 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;
|
const pkgJson = (await file(`${pkg.path}/package.json`).json()) as PackageJSON;
|
||||||
release.version = pkgJson.version;
|
release.version = pkgJson.version;
|
||||||
@@ -129,8 +129,8 @@ async function getReleaseEntries(dev: boolean, dry: boolean) {
|
|||||||
return releaseEntries;
|
return releaseEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateReleaseTree(dev: boolean, dry: boolean, packageName?: string, exclude?: string[]) {
|
export async function generateReleaseTree(dry: boolean, devTag?: string, packageName?: string, exclude?: string[]) {
|
||||||
let releaseEntries = await getReleaseEntries(dev, dry);
|
let releaseEntries = await getReleaseEntries(dry, devTag);
|
||||||
// Try to early return if the package doesn't have deps
|
// Try to early return if the package doesn't have deps
|
||||||
if (packageName && packageName !== 'all') {
|
if (packageName && packageName !== 'all') {
|
||||||
const releaseEntry = releaseEntries.find((entry) => entry.name === packageName);
|
const releaseEntry = releaseEntries.find((entry) => entry.name === packageName);
|
||||||
|
|||||||
@@ -30,15 +30,29 @@ program
|
|||||||
)
|
)
|
||||||
.option('--dry', 'skips actual publishing and outputs logs instead', dryInput)
|
.option('--dry', 'skips actual publishing and outputs logs instead', dryInput)
|
||||||
.option('--dev', 'publishes development versions and skips tagging / github releases', devInput)
|
.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();
|
.parse();
|
||||||
|
|
||||||
const { exclude, dry, dev } = program.opts<{ dev: boolean; dry: boolean; exclude: string[] }>();
|
const {
|
||||||
const [packageName] = program.processedArgs as [string];
|
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) {
|
for (const branch of tree) {
|
||||||
startGroup(`Releasing ${branch.map((entry) => `${entry.name}@${entry.version}`).join(', ')}`);
|
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();
|
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
|
// Sanity check against the registry first
|
||||||
if (await checkRegistry(release)) {
|
if (await checkRegistry(release)) {
|
||||||
info(`${release.name}@${release.version} already published, skipping.`);
|
info(`${release.name}@${release.version} already published, skipping.`);
|
||||||
@@ -51,11 +51,11 @@ export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: b
|
|||||||
if (dry) {
|
if (dry) {
|
||||||
info(`[DRY] Releasing ${release.name}@${release.version}`);
|
info(`[DRY] Releasing ${release.name}@${release.version}`);
|
||||||
} else {
|
} 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
|
// && !devTag just to be sure
|
||||||
if (doGitRelease && !dev) await gitTagAndRelease(release, dry);
|
if (doGitRelease && !devTag) await gitTagAndRelease(release, dry);
|
||||||
|
|
||||||
if (dry) return;
|
if (dry) return;
|
||||||
|
|
||||||
@@ -77,9 +77,9 @@ export async function releasePackage(release: ReleaseEntry, dev: boolean, dry: b
|
|||||||
}, 15_000);
|
}, 15_000);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (dev) {
|
if (devTag) {
|
||||||
// Send and forget, deprecations are less important than releasing other dev versions and can be done manually
|
// 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()
|
.nothrow()
|
||||||
// eslint-disable-next-line promise/prefer-await-to-then
|
// eslint-disable-next-line promise/prefer-await-to-then
|
||||||
.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`;
|
await $`pnpm --filter=create-discord-bot run rename-to-app`;
|
||||||
// eslint-disable-next-line require-atomic-updates
|
// eslint-disable-next-line require-atomic-updates
|
||||||
release.name = 'create-discord-app';
|
release.name = 'create-discord-app';
|
||||||
await releasePackage(release, dev, dry, false);
|
await releasePackage(release, dry, devTag, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user