diff --git a/.changeset/config.json b/.changeset/config.json index 6c07d22e1d0..cc10ab5745e 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,10 +7,40 @@ "baseBranch": "v-next", "updateInternalDependencies": "patch", "ignore": [ + "@nomicfoundation/config", "@nomicfoundation/example-project", "@nomicfoundation/template-package", "template-*" ], + "fixed": [ + [ + "hardhat", + "@nomicfoundation/hardhat-errors", + "@nomicfoundation/hardhat-ethers-chai-matchers", + "@nomicfoundation/hardhat-ignition", + "@nomicfoundation/ignition-core", + "@nomicfoundation/hardhat-ignition-ethers", + "@nomicfoundation/ignition-ui", + "@nomicfoundation/hardhat-ignition-viem", + "@nomicfoundation/hardhat-keystore", + "@nomicfoundation/hardhat-mocha", + "@nomicfoundation/hardhat-network-helpers", + "@nomicfoundation/hardhat-node-test-reporter", + "@nomicfoundation/hardhat-node-test-runner", + "@nomicfoundation/hardhat-test-utils", + "@nomicfoundation/hardhat-typechain", + "@nomicfoundation/hardhat-utils", + "@nomicfoundation/hardhat-toolbox-mocha-ethers", + "@nomicfoundation/hardhat-viem", + "@nomicfoundation/hardhat-zod-utils" + ], + [ + "@nomicfoundation/hardhat-toolbox-viem" + ], + [ + "@nomicfoundation/hardhat-ethers" + ] + ], "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true } diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index f1d165f6855..153734b4603 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -25,12 +25,13 @@ runs: - uses: pnpm/action-setup@v4 with: version: ${{ inputs.pnpm-version }} - - uses: actions/setup-node@v4 - id: setup-node + - id: setup-node + uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: ${{ inputs.cache-save == 'true' && 'pnpm' || '' }} cache-dependency-path: "**/pnpm-lock.yaml" + registry-url: https://registry.npmjs.org - id: pnpm if: inputs.cache-save == 'false' run: pnpm store path --silent | xargs -I {} -0 echo "path={}" | tee -a $GITHUB_OUTPUT diff --git a/.github/workflows/check-changeset-added.yml b/.github/workflows/check-changeset-added.yml index d5a08438185..2b585cdf162 100644 --- a/.github/workflows/check-changeset-added.yml +++ b/.github/workflows/check-changeset-added.yml @@ -20,49 +20,19 @@ jobs: check-if-changeset: name: Check that PR has a changeset runs-on: ubuntu-latest - # don't run this check in the changesets PR - if: github.head_ref != 'changeset-release/main' steps: - - uses: actions/github-script@v7 - with: - script: | - const isMergeGroup = context.eventName === "merge_group"; + - name: Checkout the repository + uses: actions/checkout@v4 - // Merge group context - if (isMergeGroup) { - console.log("Ignore changeset check for merge group."); - return; - } + # We need to fetch the base ref because the pull request check inspects the diff between the head and the base ref + - run: git fetch origin "$GITHUB_BASE_REF":"$GITHUB_BASE_REF" - // Single PR context - const pullNumber = context.issue.number; + - name: Check if merge group is valid + if: github.event_name == 'merge_group' + run: node scripts/validate-merge-group.mjs - const { data: files } = await github.rest.pulls.listFiles({ - ...context.issue, - pull_number: pullNumber - }); - const changeset = files.find( - file => file.status === "added" && file.filename.startsWith(".changeset/") - ); - if (changeset !== undefined) { - console.log("Changeset found:", changeset.filename); - return; - } - - console.log("No changeset found"); - - - const { data: pull } = await github.rest.pulls.get({ - ...context.issue, - pull_number: pullNumber - }); - const noChangesetNeededLabel = pull.labels - .some(l => l.name === "no changeset needed"); - if (noChangesetNeededLabel) { - console.log('The PR is labeled as "no changeset needed"'); - return; - } - - console.log('The PR is not labeled as "no changeset needed"'); - - process.exit(1); + - name: Check if PR has a changeset + if: github.event_name == 'pull_request' + env: + GITHUB_EVENT_PULL_REQUEST_LABELS: ${{ toJson(github.event.pull_request.labels) }} + run: node scripts/validate-pull-request.mjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index afc3d2560e4..3997a3db9be 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,30 +1,89 @@ name: Release on: + workflow_dispatch: push: branches: - - main + - v-next + +defaults: + run: + shell: bash jobs: release: name: Release runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: write # This allows us to push to the repository and create GitHub releases + pull-requests: write # This allows us to create pull requests steps: - name: Checkout Repo uses: actions/checkout@v4 with: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 + # NOTE: If we use default GITHUB_TOKEN to create the release PR, the checks on the release PR will not be triggered automatically + token: ${{ secrets.RELEASE_GITHUB_TOKEN || github.token }} - - uses: ./.github/actions/setup-env + - name: Set up the environment + uses: ./.github/actions/setup-env - name: Install Dependencies run: pnpm install --frozen-lockfile --prefer-offline - - name: Create Release Pull Request + - name: Create release Pull Request + id: pr + env: + # NOTE: If we use the default GITHUB_TOKEN to create the release PR, the checks on the release PR will not be triggered automatically + GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN || github.token }} uses: changesets/action@v1 + with: + version: node scripts/version-alpha.mjs + + - name: Check if release needs to be published + id: before + if: steps.pr.outputs.hasChangesets == 'false' + run: node scripts/check-release.mjs + + - name: Build All Packages + if: steps.before.outputs.released == 'false' + run: pnpm run --recursive -no-bail --filter './v-next/**' --if-present build + + - name: Publish All Packages (dry-run) + if: steps.before.outputs.released == 'false' + run: pnpm publish --filter "./v-next/**" -r --no-git-checks --tag next --access public --dry-run + + - name: Publish All Packages + id: publish + if: steps.before.outputs.released == 'false' + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + NPM_CONFIG_PROVENANCE: true + run: pnpm publish --filter "./v-next/**" -r --no-git-checks --tag next --access public + + - name: Check if release was published + id: after + if: steps.before.outputs.released == 'false' + run: node scripts/check-release.mjs + + - name: Prepare GitHub release + id: release + if: steps.before.outputs.released == 'false' && steps.after.outputs.released == 'true' + run: node scripts/prepare-github-release.mjs + + - name: Create GitHub Release + if: steps.before.outputs.released == 'false' && steps.after.outputs.released == 'true' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} + uses: galargh/action-gh-release@571276229e7c9e6ea18f99bad24122a4c3ec813f # https://github.com/galargh/action-gh-release/pull/1 + with: + # We want the GitHub releases to be verified and published by a human because they are automatically pulled into the website + draft: true + tag_name: hardhat@${{ steps.release.outputs.version }} + generate_release_notes: false + target_commitish: ${{ github.sha }} + make_latest: ${{ steps.release.outputs.latest == 'true' }} + prerelease: ${{ steps.release.outputs.prerelease == 'true' }} + body: ${{ steps.release.outputs.body }} + token: ${{ github.token }} diff --git a/scripts/check-release.mjs b/scripts/check-release.mjs new file mode 100644 index 00000000000..3c0df90aedd --- /dev/null +++ b/scripts/check-release.mjs @@ -0,0 +1,24 @@ +// @ts-check + +import { appendFile } from "node:fs/promises"; + +import { readPackage, isPackageReleasedToNpm } from "./lib/packages.mjs"; + +/** + * The function checks whether the version of hardhat from its' package.json is available in the NPM registry + * It appends this information to the GITHUB_OUTPUT file (this is an env variable available in the GitHub Actions environment) + */ +async function checkRelease() { + if (process.env.GITHUB_OUTPUT === undefined) { + throw new Error("GITHUB_OUTPUT is not defined"); + } + + const hardhat = await readPackage("hardhat"); + const released = await isPackageReleasedToNpm(hardhat.name, hardhat.version); + + console.log(`released: ${released}`); + + await appendFile(process.env.GITHUB_OUTPUT, `released=${released}\n`); +} + +await checkRelease(); diff --git a/scripts/lib/changesets.mjs b/scripts/lib/changesets.mjs new file mode 100644 index 00000000000..b7e73a96a70 --- /dev/null +++ b/scripts/lib/changesets.mjs @@ -0,0 +1,71 @@ +// @ts-check + +import { exec as execSync } from "node:child_process"; +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; +import { promisify } from "node:util"; + +const exec = promisify(execSync); + +const changesetDir = ".changeset"; + +/** + * Read all the changesets that have not yet been applied + * based on the pre.json file. + */ +export async function readAllNewChangsets() { + const allChangesetNames = (await readdir(changesetDir)) + .filter((file) => file.endsWith(".md")) + .map((file) => file.slice(0, -3)); + + const alreadyAppliedChangesetNames = JSON.parse( + (await readFile(path.join(changesetDir, "pre.json"))).toString() + ); + + const newChangesetNames = allChangesetNames.filter( + (name) => !alreadyAppliedChangesetNames.changesets.includes(name) + ); + + const changesets = []; + + for (const newChangeSetName of newChangesetNames) { + const changesetFilePath = path.join(changesetDir, `${newChangeSetName}.md`); + + const changesetContent = await readFile(changesetFilePath, "utf-8"); + + const { content, frontMatter } = parseFrontMatter(changesetContent); + const commitHash = await getAddingCommit(changesetFilePath); + + changesets.push({ + frontMatter, + content, + path: changesetFilePath, + commitHash, + }); + } + + return changesets; +} + +function parseFrontMatter(markdown) { + const match = markdown.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); + if (!match) { + return { frontMatter: null, content: markdown }; + } + + return { + frontMatter: match[1], + content: match[2], + }; +} + +async function getAddingCommit(filePath) { + try { + const { stdout } = await exec( + `git log --diff-filter=A --follow --format=%h -- "${filePath}"` + ); + return stdout.trim() || null; + } catch { + return null; + } +} diff --git a/scripts/lib/packages.mjs b/scripts/lib/packages.mjs new file mode 100644 index 00000000000..a85fa307617 --- /dev/null +++ b/scripts/lib/packages.mjs @@ -0,0 +1,35 @@ +// @ts-check + +import { readdir, readFile } from "node:fs/promises"; + +const packagesDir = "v-next"; + +/** + * Read all the package.json files of the packages that we release to npm. + */ +export async function readAllReleasablePackages() { + const allPackageNames = (await readdir(packagesDir)) + .filter(file => !['config', 'example-project', 'template-package', 'hardhat-test-utils'].includes(file)); + + return Promise.all(allPackageNames.map(readPackage)); +} + +export async function readPackage(name) { + return JSON.parse(await readFile(`./v-next/${name}/package.json`, 'utf-8')); +} + +export async function getLatestPackageVersionFromNpm(name) { + const url = `https://registry.npmjs.org/${name}/latest`; + const response = await fetch(url); + if (response.status !== 200) { + throw new Error(`Failed to fetch ${url}: ${response.statusText}`); + } + const json = await response.json(); + return json.version; +} + +export async function isPackageReleasedToNpm(name, version) { + const url = `https://registry.npmjs.org/${name}/${version}`; + const response = await fetch(url); + return response.status === 200; +} diff --git a/scripts/prepare-github-release.mjs b/scripts/prepare-github-release.mjs new file mode 100644 index 00000000000..28f7494de85 --- /dev/null +++ b/scripts/prepare-github-release.mjs @@ -0,0 +1,89 @@ +// @ts-check + +import { appendFile } from "node:fs/promises"; +import { readFile } from "node:fs/promises"; + +import { getLatestPackageVersionFromNpm, readPackage } from "./lib/packages.mjs"; + +// The regex was taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; + +function isPrerelease(version) { + const [, , , , prerelease] = version.match(semverRegex); + return prerelease !== undefined; +} + +async function isLatest(version) { + const latestVersion = await getLatestPackageVersionFromNpm("hardhat"); + return version === latestVersion; +} + +async function getHardhatChangelogEntry(version) { + const changelog = await readFile("v-next/hardhat/CHANGELOG.md", "utf-8"); + + const lines = changelog.split('\n') + const headerIndex = lines.findIndex((line) => line == `## ${version}`) + + if (headerIndex == -1) { + throw new Error(`Changelog entry for version ${version} not found in ./v-next/hardhat/CHANGELOG.md`) + } + + const entryLines = []; + + for (const line of lines.slice(headerIndex + 1)) { + if (line.startsWith('## ')) { + break + } + if (line === '### Patch Changes') { + entryLines.push('### Changes'); + } else { + entryLines.push(line) + } + } + + return entryLines.join('\n').trim() +} + +async function getReleaseBody(version) { + const lines = [ + "This Hardhat 3 Alpha release [short summary of the changes].", + "", + await getHardhatChangelogEntry(version), + "", + "---", + "> 💡 **The Nomic Foundation is hiring! Check [our open positions](https://www.nomic.foundation/jobs).**", + "---", + ]; + return lines.join("\n"); +} + +/** + * The function calculates the information that we need to create a new GitHub Release. Namely, the hardhat version + * whether the release should be marked as prerelease and latest, and the body that should be used for the release. + * It appends this information to the GITHUB_OUTPUT file (this is an env variable available in the GitHub Actions environment) + */ +async function prepareGitHubRelease() { + if (process.env.GITHUB_OUTPUT === undefined) { + throw new Error("GITHUB_OUTPUT is not defined"); + } + + const hardhat = await readPackage("hardhat"); + + const version = hardhat.version; + console.log(`version: ${version}`); + await appendFile(process.env.GITHUB_OUTPUT, `version=${version}\n`); + + const prerelease = isPrerelease(hardhat.version); + console.log(`prerelease: ${prerelease}`); + await appendFile(process.env.GITHUB_OUTPUT, `prerelease=${prerelease}\n`); + + const latest = await isLatest(hardhat.version); + console.log(`latest: ${latest}`); + await appendFile(process.env.GITHUB_OUTPUT, `latest=${latest}\n`); + + const body = await getReleaseBody(hardhat.version); + console.log(`body: ${body}`); + await appendFile(process.env.GITHUB_OUTPUT, `body< l.name === "no changeset needed"); +} + +async function hasChangeset() { + if (process.env.GITHUB_BASE_REF === undefined) { + throw new Error("GITHUB_BASE_REF is not defined"); + } + + const { stdout } = await exec( + `git diff --name-only --diff-filter=A ${process.env.GITHUB_BASE_REF} -- ${changesetDir}` + ); + + const changesets = stdout.trim().split("\n") + .filter((file) => file.endsWith(".md")); + + return changesets.length > 0; +} + +async function validatePullRequest() { + if (isReleasePR()) { + console.log("Ignore changeset check for release PR."); + return; + } + + if (await hasNoChangesetNeededLabel()) { + console.log("The PR is labeled as 'no changeset needed'"); + return; + } + + if (await hasChangeset()) { + console.log("Changeset found"); + return; + } + + throw new Error("No changeset found"); +} + +await validatePullRequest(); diff --git a/scripts/version-alpha.mjs b/scripts/version-alpha.mjs index 6aa8551fcdc..011e1e8a248 100644 --- a/scripts/version-alpha.mjs +++ b/scripts/version-alpha.mjs @@ -1,7 +1,13 @@ -import { readdir, readFile, writeFile, stat } from "node:fs/promises"; +// @ts-check + +import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { exec } from "node:child_process"; import { promisify } from "node:util"; +import { randomUUID } from "node:crypto"; + +import { readAllNewChangsets } from "./lib/changesets.mjs"; +import { readPackage } from "./lib/packages.mjs"; const execAsync = promisify(exec); @@ -9,85 +15,40 @@ const changesetDir = ".changeset"; const packagesDir = "v-next"; /** - * This script applies changesets and creates a new Alpha version, - * based on changesets pre-release versioning. + * This script applies changesets based on changesets pre-release versioning. * * It reads all the new changesets and validates that: - * - they patch the main Hardhat package * - there are no major or minor changesets * * It then combines the new changesets to create a new changelog * section for the new version. * - * The next step is to create a release changeset that patches all of the - * packages (except Hardhat, which by definition is already covered). - * By applying a changeset to all packages we eliminate issues - * with peer depenendencies not being updated. + * The next step is to create a changeset for packages which are one major + * version ahead of all the others (v4 vs v3) if they don't exist yet. The major + * version mismatch is the reason why we cannot include them in the fixed set. * * The release changeset is then applied, bumping versions across * the packages (including the template packages). * * Finally the Hardhat packages changelog is updated with the * prepared changelog section. - * - * It is up to the user to commit and push the changes as a release - * branch. */ async function versionAlpha() { const changesets = await readAllNewChangsets(); validateChangesets(changesets); - const currentHardhatAlphaVersion = await readCurrentHardhatAlphaVersion(); - const nextHardhatAlphaVersion = incrementHardhatAlphaVersion( - currentHardhatAlphaVersion - ); - - await createAllPackageChangesetFor(nextHardhatAlphaVersion); + for (const packageName of ["@nomicfoundation/hardhat-ethers", "@nomicfoundation/hardhat-toolbox-viem"]) { + if (shouldCreateChangeset(changesets, packageName)) { + await createChangeset(packageName); + } + } await executeChangesetVersion(); - await updateHardhatChangelog(nextHardhatAlphaVersion, changesets); + const hardhat = await readPackage("hardhat"); - printFollowupInstructions(nextHardhatAlphaVersion, changesets); -} - -/** - * Read all the changesets that have not yet been applied - * based on the pre.json file. - */ -async function readAllNewChangsets() { - const allChangesetNames = (await readdir(changesetDir)) - .filter((file) => file.endsWith(".md")) - .map((file) => file.slice(0, -3)); - - const alreadyAppliedChangesetNames = JSON.parse( - await readFile(path.join(changesetDir, "pre.json")) - ); - - const newChangesetNames = allChangesetNames.filter( - (name) => !alreadyAppliedChangesetNames.changesets.includes(name) - ); - - const changesets = []; - - for (const newChangeSetName of newChangesetNames) { - const changesetFilePath = path.join(changesetDir, `${newChangeSetName}.md`); - - const changesetContent = await readFile(changesetFilePath, "utf-8"); - - const { content, frontMatter } = parseFrontMatter(changesetContent); - const commitHash = await getAddingCommit(changesetFilePath); - - changesets.push({ - frontMatter, - content, - path: changesetFilePath, - commitHash, - }); - } - - return changesets; + await updateHardhatChangelog(hardhat.version, changesets); } /** @@ -95,25 +56,17 @@ async function readAllNewChangsets() { * changeset, logging and killing the script otherwise. * * The validations are: - * - every changeset must include a `"hardhat": patch` entry * - no major or minor changesets are allowed */ function validateChangesets(changesets) { if (changesets.length === 0) { - console.log("Error: No new changesets found."); - process.exit(1); + console.log("No new changesets found."); + process.exit(0); } let validationFailed = false; for (const { frontMatter, path: changesetPath } of changesets) { - if (!/^\s*"hardhat": patch$/m.test(frontMatter)) { - validationFailed = true; - console.log( - `Error: ${changesetPath}: No "hardhat: patch", every Alpha changeset must include hardhat` - ); - } - if (/: (major|minor)\s*$/m.test(frontMatter)) { validationFailed = true; console.log( @@ -128,58 +81,39 @@ function validateChangesets(changesets) { } /** - * Read the current Alpha version based on the hardhat package.json + * Checks whether a new changeset should be created for the package. */ -async function readCurrentHardhatAlphaVersion() { - const hardhatPackageJson = JSON.parse( - await readFile(path.join("v-next", "hardhat", "package.json")) - ); - - return hardhatPackageJson.version; -} - -/** - * Increment the Alpha version by 1. We assume that the `next` - * tag is always used. - */ -function incrementHardhatAlphaVersion(version) { - const match = version.match(/(\d+\.\d+\.\d+)-next\.(\d+)/); - - if (!match) { - console.log(`Unsupported version format: ${version}`); - process.exit(1); +function shouldCreateChangeset(changesets, packageName) { + if (changesets.length === 0) { + return false; } - const [, base, num] = match; - const nextNum = Number(num) + 1; + for (const { frontMatter } of changesets) { + if (frontMatter.split("\n").some((line) => line.startsWith(`"${packageName}": patch`))) { + return false; + } + } - return `${base}-next.${nextNum}`; + return true; } /** - * Write a changeset file that has one entry for every package - * under `./v-next` excluding the hardhat package (this is - * covered definitionally because of the validation rules). + * Creates a new patch changeset file for the pacakge. */ -async function createAllPackageChangesetFor(nextHardhatAlphaVersion) { - const releaseChangesetPath = path.join( +async function createChangeset(packageName) { + const changesetPath = path.join( changesetDir, - `release-${nextHardhatAlphaVersion}.md` + `${randomUUID()}.md` ); - const packageNames = await readAllPackageNames(); - - const releaseChangesetContent = `--- -${packageNames - .filter((name) => name !== "hardhat" && name !== "@nomicfoundation/config") - .map((name) => `"${name}": patch`) - .join("\n")} ---- - -Hardhat 3 Alpha release (${new Date().toISOString()}) -`; + const releaseChangesetContent = [ + '---', + `"${packageName}": patch`, + '---', + '', + ].join('\n'); - await writeFile(releaseChangesetPath, releaseChangesetContent); + await writeFile(changesetPath, releaseChangesetContent); } /** @@ -188,16 +122,16 @@ Hardhat 3 Alpha release (${new Date().toISOString()}) */ async function executeChangesetVersion() { await execAsync("pnpm changeset version"); - await execAsync("pnpm install"); + await execAsync("pnpm install --lockfile-only"); } /** * Prepend a new changelog section to the Hardhat package's * changelog based on the new changesets. */ -async function updateHardhatChangelog(nextHardhatAlphaVersion, changesets) { +async function updateHardhatChangelog(hardhatVersion, changesets) { const newChangelogSection = generateChangelogFrom( - nextHardhatAlphaVersion, + hardhatVersion, changesets ); @@ -217,54 +151,10 @@ async function updateHardhatChangelog(nextHardhatAlphaVersion, changesets) { await writeFile(hardhatChangelogPath, newChangelog); } -function printFollowupInstructions(nextHardhatAlphaVersion, changesets) { - console.log(` - -# ${nextHardhatAlphaVersion} - -${generateReleaseMessage(changesets)} -`); -} - -async function readAllPackageNames() { - const ignoredChangesetPackages = JSON.parse( - await readFile(path.join(changesetDir, "config.json")) - ).ignore; - - const subdirs = await readdir(packagesDir); - - const packageNames = []; - - for (const dir of subdirs) { - const packageJsonPath = path.join(packagesDir, dir, "package.json"); - - try { - const stats = await stat(packageJsonPath); - - if (!stats.isFile()) { - continue; - } - - const pkgJson = JSON.parse(await readFile(packageJsonPath, "utf8")); - - if (ignoredChangesetPackages.includes(pkgJson.name)) { - continue; - } - - packageNames.push(pkgJson.name); - } catch (error) { - console.log(error); - process.exit(1); - } - } - - return packageNames.sort(); -} - -function generateChangelogFrom(nextHardhatAlphaVersion, changesets) { +function generateChangelogFrom(hardhatVersion, changesets) { return `# hardhat -## ${nextHardhatAlphaVersion} +## ${hardhatVersion} ### Patch Changes @@ -272,19 +162,6 @@ ${generateChangesTextFrom(changesets)} `; } -function generateReleaseMessage(changesets) { - return `This Hardhat 3 Alpha release [short summary of the changes]. - -### Changes - -${generateChangesTextFrom(changesets)} - ---- -> 💡 **The Nomic Foundation is hiring! Check [our open positions](https://www.nomic.foundation/jobs).** ---- -`; -} - function generateChangesTextFrom(changesets) { return changesets .map(({ content, commitHash }) => @@ -302,27 +179,4 @@ function generateChangesTextFrom(changesets) { .join("\n"); } -function parseFrontMatter(markdown) { - const match = markdown.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); - if (!match) { - return { frontMatter: null, content: markdown }; - } - - return { - frontMatter: match[1], - content: match[2], - }; -} - -async function getAddingCommit(filePath) { - try { - const { stdout } = await execAsync( - `git log --diff-filter=A --follow --format=%h -- "${filePath}"` - ); - return stdout.trim() || null; - } catch { - return null; - } -} - await versionAlpha(); diff --git a/v-next/hardhat/test/internal/cli/init/init.ts b/v-next/hardhat/test/internal/cli/init/init.ts index e8eb8f63aa4..eaafcb90011 100644 --- a/v-next/hardhat/test/internal/cli/init/init.ts +++ b/v-next/hardhat/test/internal/cli/init/init.ts @@ -250,10 +250,14 @@ describe("installProjectDependencies", async () => { // NOTE: This test is slow because it installs dependencies over the network. // It tests installation for all the templates, but only with the npm as the // package manager. We also support pnpm and yarn. - it.skip( + it( `should install all the ${template.name} template dependencies in an empty project if the user opts-in to the installation`, { - skip: process.env.HARDHAT_DISABLE_SLOW_TESTS === "true", + skip: + process.env.HARDHAT_DISABLE_SLOW_TESTS === "true" || + process.env.GITHUB_EVENT_NAME === "push" || // TODO: This check should be limited to push events associated with a release PR merge + process.env.GITHUB_EVENT_NAME === "merge_group" || // TODO: This check should be limited to merge_group events associated with a release PR merge + process.env.GITHUB_HEAD_REF?.startsWith("changeset-release/"), }, async () => { await writeUtf8File("package.json", JSON.stringify({ type: "module" })); @@ -286,7 +290,11 @@ describe("installProjectDependencies", async () => { it( "should install any existing template dependencies that are out of date if the user opts-in to the update", { - skip: process.env.HARDHAT_DISABLE_SLOW_TESTS === "true", + skip: + process.env.HARDHAT_DISABLE_SLOW_TESTS === "true" || + process.env.GITHUB_EVENT_NAME === "push" || // TODO: This check should be limited to push events associated with a release PR merge + process.env.GITHUB_EVENT_NAME === "merge_group" || // TODO: This check should be limited to merge_group events associated with a release PR merge + process.env.GITHUB_HEAD_REF?.startsWith("changeset-release/"), }, async () => { const template = await getTemplate("mocha-ethers");