diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 69851d1a..cc4af45a 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -69,14 +69,14 @@ runs: if: ${{ inputs.rustfmt == 'true' }} uses: dtolnay/rust-toolchain@master with: - toolchain: ${{ env.TOOLCHAIN_FORMAT }} + toolchain: ${{ env.TOOLCHAIN_NIGHTLY }} components: rustfmt - name: Install Clippy if: ${{ inputs.clippy == 'true' }} uses: dtolnay/rust-toolchain@master with: - toolchain: ${{ env.TOOLCHAIN_LINT }} + toolchain: ${{ env.TOOLCHAIN_NIGHTLY }} components: clippy - name: Install Solana diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d69dee93..c1963d3f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -98,26 +98,6 @@ jobs: - name: Run cargo-audit run: pnpm rust:audit - semver_rust: - name: Check semver Rust - runs-on: ubuntu-latest - steps: - - name: Git Checkout - uses: actions/checkout@v4 - - - name: Setup Environment - uses: ./.github/actions/setup - with: - cargo-cache-key: cargo-semver - - - name: Install cargo-audit - uses: taiki-e/install-action@v2 - with: - tool: cargo-semver-checks - - - name: Run semver checks - run: pnpm rust:semver - spellcheck_rust: name: Spellcheck Rust runs-on: ubuntu-latest @@ -220,7 +200,10 @@ jobs: path: ./**/*.so key: ${{ runner.os }}-builds-${{ github.sha }} - - name: Test Client JS + - name: Build dependency + run: pnpm clients:js:build + + - name: Test run: pnpm clients:js-legacy:test test_client_cli: diff --git a/.github/workflows/publish-js-client.yml b/.github/workflows/publish-js-client.yml index fcb29c05..4f42e85b 100644 --- a/.github/workflows/publish-js-client.yml +++ b/.github/workflows/publish-js-client.yml @@ -3,6 +3,14 @@ name: Publish JS Client on: workflow_dispatch: inputs: + package_path: + description: Path to directory with package to release + required: true + default: 'clients/js' + type: choice + options: + - clients/js + - clients/js-legacy level: description: Version level required: true @@ -28,8 +36,8 @@ on: default: true jobs: - test_js: - name: Test JS client + test: + name: Test JS package runs-on: ubuntu-latest steps: - name: Git Checkout @@ -39,42 +47,71 @@ jobs: uses: ./.github/actions/setup with: solana: true + cargo-cache-key: cargo-js-test-publish-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-js-test-publish + + - name: Format + run: pnpm zx ./scripts/js/format.mjs "${{ inputs.package_path }}" - - name: Format JS Client - run: pnpm clients:js:format + - name: Lint + run: pnpm zx ./scripts/js/lint.mjs "${{ inputs.package_path }}" - - name: Lint JS Client - run: pnpm clients:js:lint + - name: Build Programs + run: pnpm programs:build - - name: Test JS Client - run: pnpm clients:js:test + - name: Test + run: pnpm zx ./scripts/js/test.mjs "${{ inputs.package_path }}" - publish_js: - name: Publish JS client + publish: + name: Publish JS package runs-on: ubuntu-latest - needs: test_js + needs: test permissions: contents: write steps: - name: Git Checkout uses: actions/checkout@v4 + with: + token: ${{ secrets.ANZA_TEAM_PAT }} + fetch-depth: 0 # get the whole history for git-cliff - name: Setup Environment uses: ./.github/actions/setup - - name: Ensure NPM_TOKEN variable is set + - name: Ensure SOLANA_NPM_TOKEN variable is set + env: + token: ${{ secrets.SOLANA_NPM_TOKEN }} + if: ${{ env.token == '' }} + run: | + echo "The SOLANA_NPM_TOKEN secret variable is not set" + echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." + exit 1 + + - name: Ensure SOLANA_PROGRAM_NPM_TOKEN variable is set env: - token: ${{ secrets.NPM_TOKEN }} + token: ${{ secrets.SOLANA_PROGRAM_NPM_TOKEN }} if: ${{ env.token == '' }} run: | - echo "The NPM_TOKEN secret variable is not set" + echo "The SOLANA_PROGRAM_NPM_TOKEN secret variable is not set" echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." exit 1 - name: NPM Authentication - run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}" env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + SOLANA_NPM_TOKEN: ${{ secrets.SOLANA_NPM_TOKEN }} + SOLANA_PROGRAM_NPM_TOKEN: ${{ secrets.SOLANA_PROGRAM_NPM_TOKEN }} + shell: bash + run: | + cd "${{ inputs.package_path }}" + org="$(jq '.name|split("/")|.[0]' package.json)" + if [[ $org == "\"@solana-program\"" ]] then + pnpm config set '//registry.npmjs.org/:_authToken' "${SOLANA_PROGRAM_NPM_TOKEN}" + elif [[ $org == "\"@solana\"" ]] then + pnpm config set '//registry.npmjs.org/:_authToken' "${SOLANA_NPM_TOKEN}" + else + echo "Unknown organization: $org" + exit 1 + fi - name: Set Git Author run: | @@ -83,13 +120,27 @@ jobs: - name: Publish JS Client id: publish - run: pnpm clients:js:publish ${{ inputs.level }} ${{ inputs.tag }} + run: pnpm js:publish "${{ inputs.package_path }}" ${{ inputs.level }} ${{ inputs.tag }} - name: Push Commit and Tag run: git push origin --follow-tags + - name: Generate a changelog + if: github.event.inputs.create_release == 'true' + uses: orhun/git-cliff-action@v3 + with: + config: "scripts/cliff.toml" + args: | + "${{ steps.publish.outputs.old_git_tag }}"..main + --include-path "${{ inputs.package_path }}/**" + --github-repo "${{ github.repository }}" + env: + OUTPUT: TEMP_CHANGELOG.md + GITHUB_REPO: ${{ github.repository }} + - name: Create GitHub release if: github.event.inputs.create_release == 'true' uses: ncipollo/release-action@v1 with: - tag: js@v${{ steps.publish.outputs.new_version }} + tag: ${{ steps.publish.outputs.new_git_tag }} + bodyFile: TEMP_CHANGELOG.md diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-rust.yml similarity index 50% rename from .github/workflows/publish-cli.yml rename to .github/workflows/publish-rust.yml index f025b916..f3c667b7 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-rust.yml @@ -1,8 +1,16 @@ -name: Publish CLI +name: Publish Rust Crate on: workflow_dispatch: inputs: + package_path: + description: Path to directory with package to release + required: true + default: 'clients/cli' + type: choice + options: + - clients/cli + - program level: description: Level required: true @@ -12,15 +20,6 @@ on: - patch - minor - major - - rc - - beta - - alpha - - release - - version - version: - description: Version - required: false - type: string dry_run: description: Dry run required: true @@ -34,7 +33,7 @@ on: jobs: test: - name: Test + name: Test Rust Crate runs-on: ubuntu-latest steps: - name: Git Checkout @@ -43,22 +42,34 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup with: - cargo-cache-key: cargo-cli clippy: true rustfmt: true solana: true + cargo-cache-key: cargo-test-publish-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-test-publish + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-semver-checks - name: Format - run: pnpm clients:cli:format + run: pnpm zx ./scripts/rust/format.mjs "${{ inputs.package_path }}" - name: Lint - run: pnpm clients:cli:lint + run: pnpm zx ./scripts/rust/lint.mjs "${{ inputs.package_path }}" + + - name: Build programs + run: pnpm programs:build - name: Test - run: pnpm clients:cli:test + run: pnpm zx ./scripts/rust/test.mjs "${{ inputs.package_path }}" - publish_cli: - name: Publish CLI + - name: Check semver + run: pnpm rust:semver ${{ inputs.package_path }} --release-type ${{ inputs.level }} + + publish: + name: Publish Rust Crate runs-on: ubuntu-latest needs: test permissions: @@ -66,22 +77,23 @@ jobs: steps: - name: Git Checkout uses: actions/checkout@v4 + with: + token: ${{ secrets.ANZA_TEAM_PAT }} + fetch-depth: 0 # get the whole history for git-cliff - name: Setup Environment uses: ./.github/actions/setup with: - cargo-cache-key: cargo-publish-cli - cargo-cache-fallback-key: cargo-cli - clippy: true - rustfmt: true + cargo-cache-key: cargo-publish-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-publish - name: Install Cargo Release run: which cargo-release || cargo install cargo-release - name: Ensure CARGO_REGISTRY_TOKEN variable is set env: - token: ${{ secrets.CARGO_REGISTRY_TOKEN }} - if: ${{ env.token == '' }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + if: ${{ env.CARGO_REGISTRY_TOKEN == '' }} run: | echo "The CARGO_REGISTRY_TOKEN secret variable is not set" echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." @@ -92,31 +104,35 @@ jobs: git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" - - name: Publish + - name: Publish Crate id: publish env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: | - if [ "${{ inputs.level }}" == "version" ]; then - LEVEL=${{ inputs.version }} - else - LEVEL=${{ inputs.level }} - fi - if [ "${{ inputs.dry_run }}" == "true" ]; then OPTIONS="--dry-run" else OPTIONS="" fi - pnpm clients:cli:publish $LEVEL $OPTIONS + pnpm rust:publish "${{ inputs.package_path }}" "${{ inputs.level }}" $OPTIONS - - name: Push Commit and Tag - if: github.event.inputs.dry_run != 'true' - run: git push origin --follow-tags + - name: Generate a changelog + if: github.event.inputs.create_release == 'true' + uses: orhun/git-cliff-action@v3 + with: + config: "scripts/cliff.toml" + args: | + "${{ steps.publish.outputs.old_git_tag }}"..main + --include-path "${{ inputs.package_path }}/**" + --github-repo "${{ github.repository }}" + env: + OUTPUT: TEMP_CHANGELOG.md + GITHUB_REPO: ${{ github.repository }} - name: Create GitHub release if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true' uses: ncipollo/release-action@v1 with: - tag: cli@v${{ steps.publish.outputs.new_version }} + tag: ${{ steps.publish.outputs.new_git_tag }} + bodyFile: TEMP_CHANGELOG.md diff --git a/Cargo.toml b/Cargo.toml index be8c90bb..a66c654d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,16 @@ solana = "2.2.0" # Specify Rust toolchains for rustfmt, clippy, and build. # Any unprovided toolchains default to stable. [workspace.metadata.toolchains] -format = "nightly-2024-11-22" -lint = "nightly-2024-11-22" +nightly = "nightly-2024-11-22" [workspace.metadata.spellcheck] config = "scripts/spellcheck.toml" +[workspace.metadata.release] +pre-release-commit-message = "Publish {{crate_name}} v{{version}}" +tag-message = "Publish {{crate_name}} v{{version}}" +consolidate-commits = false + [workspace.lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ diff --git a/clients/js-legacy/package.json b/clients/js-legacy/package.json index 76693e57..0082ee7a 100644 --- a/clients/js-legacy/package.json +++ b/clients/js-legacy/package.json @@ -12,6 +12,7 @@ } }, "scripts": { + "prepublishOnly": "pnpm build", "clean": "rm -rf dist/*", "build": "rm -rf dist/* && tsup && tsc -p ./tsconfig.declarations.json", "build:program": "cargo build-sbf --manifest-path=../../program/Cargo.toml", diff --git a/clients/js/package.json b/clients/js/package.json index c1ec94bd..16da0741 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -10,6 +10,7 @@ } }, "scripts": { + "prepublishOnly": "pnpm build", "clean": "rm -fr dist/*", "build": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json && ./ts-fixup.sh", "test": "tsc -p tsconfig.json", diff --git a/package.json b/package.json index cabc1d9f..97fe3de9 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,26 @@ { "private": true, "scripts": { - "programs:build": "zx ./scripts/program/build.mjs", - "programs:test": "zx ./scripts/program/test.mjs", - "programs:format": "zx ./scripts/program/format.mjs", - "programs:lint": "zx ./scripts/program/lint.mjs", + "programs:build": "zx ./scripts/rust/build-sbf.mjs program", + "programs:test": "zx ./scripts/rust/test.mjs program", + "programs:format": "zx ./scripts/rust/format.mjs program", + "programs:lint": "zx ./scripts/rust/lint.mjs program", "solana:check": "zx ./scripts/check-solana-version.mjs", "solana:link": "zx ./scripts/link-solana-version.mjs", - "clients:js:format": "zx ./scripts/client/format-js.mjs", - "clients:js:lint": "zx ./scripts/client/lint-js.mjs", - "clients:js:publish": "zx ./scripts/client/publish-js.mjs", - "clients:js:test": "zx ./scripts/client/test-js.mjs", - "clients:js-legacy:format": "zx ./scripts/client/format-js-legacy.mjs", - "clients:js-legacy:lint": "zx ./scripts/client/lint-js-legacy.mjs", - "clients:js-legacy:publish": "zx ./scripts/client/publish-js-legacy.mjs", - "clients:js-legacy:test": "zx ./scripts/client/test-js-legacy.mjs", - "clients:cli:format": "zx ./scripts/client/format-cli.mjs", - "clients:cli:lint": "zx ./scripts/client/lint-cli.mjs", - "clients:cli:publish": "zx ./scripts/client/publish-cli.mjs", - "clients:cli:test": "zx ./scripts/client/test-cli.mjs", + "clients:js:build": "zx ./scripts/js/build.mjs clients/js", + "clients:js:format": "zx ./scripts/js/format.mjs clients/js", + "clients:js:lint": "zx ./scripts/js/lint.mjs clients/js", + "clients:js:test": "zx ./scripts/js/test.mjs clients/js", + "clients:js-legacy:build": "zx ./scripts/js/build.mjs clients/js-legacy", + "clients:js-legacy:format": "zx ./scripts/js/format.mjs clients/js-legacy", + "clients:js-legacy:lint": "zx ./scripts/js/lint.mjs clients/js-legacy", + "clients:js-legacy:test": "zx ./scripts/js/test.mjs clients/js-legacy", + "clients:cli:format": "zx ./scripts/rust/format.mjs clients/cli", + "clients:cli:lint": "zx ./scripts/rust/lint.mjs clients/cli", + "clients:cli:test": "zx ./scripts/rust/test.mjs clients/cli", "template:upgrade": "zx ./scripts/upgrade-template.mjs", + "rust:audit": "zx ./scripts/rust/audit.mjs", "rust:spellcheck": "cargo spellcheck --code 1", - "rust:audit": "zx ./scripts/audit-rust.mjs", "rust:semver": "cargo semver-checks" }, "devDependencies": { diff --git a/scripts/ci/set-env.mjs b/scripts/ci/set-env.mjs index 276d37bf..44f3b036 100644 --- a/scripts/ci/set-env.mjs +++ b/scripts/ci/set-env.mjs @@ -2,5 +2,4 @@ import { getSolanaVersion, getToolchain } from '../utils.mjs'; await $`echo "SOLANA_VERSION=${getSolanaVersion()}" >> $GITHUB_ENV`; -await $`echo "TOOLCHAIN_FORMAT=${getToolchain('format')}" >> $GITHUB_ENV`; -await $`echo "TOOLCHAIN_LINT=${getToolchain('lint')}" >> $GITHUB_ENV`; +await $`echo "TOOLCHAIN_NIGHTLY=${getToolchain('nightly')}" >> $GITHUB_ENV`; diff --git a/scripts/client/format-js-legacy.mjs b/scripts/client/format-js-legacy.mjs deleted file mode 100644 index a7cf415f..00000000 --- a/scripts/client/format-js-legacy.mjs +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -// Format the client using Prettier. -cd(path.join(workingDirectory, 'clients', 'js-legacy')); -await $`pnpm install`; -await $`pnpm format ${cliArguments()}`; diff --git a/scripts/client/lint-js.mjs b/scripts/client/lint-js.mjs deleted file mode 100644 index f5583e2c..00000000 --- a/scripts/client/lint-js.mjs +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -// Check the client using ESLint. -cd(path.join(workingDirectory, 'clients', 'js')); -await $`pnpm install`; -await $`pnpm lint ${cliArguments()}`; diff --git a/scripts/client/publish-cli.mjs b/scripts/client/publish-cli.mjs deleted file mode 100644 index 8dc0f4be..00000000 --- a/scripts/client/publish-cli.mjs +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, getCargo, workingDirectory } from '../utils.mjs'; - -const dryRun = argv['dry-run'] ?? false; -const [level] = cliArguments(); -if (!level) { - throw new Error('A version level — e.g. "path" — must be provided.'); -} - -// Go to the client directory and install the dependencies. -cd(path.join(workingDirectory, 'clients', 'rust')); - -// Publish the new version. -const releaseArgs = dryRun - ? [] - : ['--no-push', '--no-tag', '--no-confirm', '--execute']; -await $`cargo release ${level} ${releaseArgs}`; - -// Stop here if this is a dry run. -if (dryRun) { - process.exit(0); -} - -// Get the new version. -const newVersion = getCargo(path.join('clients', 'cli')).package.version; - -// Expose the new version to CI if needed. -if (process.env.CI) { - await $`echo "new_version=${newVersion}" >> $GITHUB_OUTPUT`; -} - -// Soft reset the last commit so we can create our own commit and tag. -await $`git reset --soft HEAD~1`; - -// Commit the new version. -await $`git commit -am "Publish Rust client v${newVersion}"`; - -// Tag the new version. -await $`git tag -a cli@v${newVersion} -m "Rust client v${newVersion}"`; diff --git a/scripts/client/publish-js.mjs b/scripts/client/publish-js.mjs deleted file mode 100644 index 51df1888..00000000 --- a/scripts/client/publish-js.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -const [level, tag = 'latest'] = cliArguments(); -if (!level) { - throw new Error('A version level — e.g. "path" — must be provided.'); -} - -// Go to the client directory and install the dependencies. -cd(path.join(workingDirectory, 'clients', 'js')); -await $`pnpm install`; - -// Update the version. -const versionArgs = [ - '--no-git-tag-version', - ...(level.startsWith('pre') ? [`--preid ${tag}`] : []), -]; -let { stdout } = await $`pnpm version ${level} ${versionArgs}`; -const newVersion = stdout.slice(1).trim(); - -// Expose the new version to CI if needed. -if (process.env.CI) { - await $`echo "new_version=${newVersion}" >> $GITHUB_OUTPUT`; -} - -// Publish the package. -// This will also build the package before publishing (see prepublishOnly script). -await $`pnpm publish --no-git-checks --tag ${tag}`; - -// Commit the new version. -await $`git commit -am "Publish JS client v${newVersion}"`; - -// Tag the new version. -await $`git tag -a js@v${newVersion} -m "JS client v${newVersion}"`; diff --git a/scripts/client/test-cli.mjs b/scripts/client/test-cli.mjs deleted file mode 100644 index d6e9c4a2..00000000 --- a/scripts/client/test-cli.mjs +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const testArgs = cliArguments(); - -const hasSolfmt = await which('solfmt', { nothrow: true }); -const sbfOutDir = path.join(workingDirectory, 'target', 'deploy'); - -// Run the tests. -cd(path.join(workingDirectory, 'clients', 'cli')); -if (hasSolfmt) { - await $`cargo test ${testArgs} 2>&1 | solfmt`; -} else { - await $`cargo test ${testArgs}`; -} diff --git a/scripts/client/test-js-legacy.mjs b/scripts/client/test-js-legacy.mjs deleted file mode 100644 index 83928cbb..00000000 --- a/scripts/client/test-js-legacy.mjs +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -// Build the client. -cd(path.join(workingDirectory, 'clients', 'js')); -await $`pnpm install`; -await $`pnpm build`; - -// Build the legacy client and run the tests. -cd(path.join(workingDirectory, 'clients', 'js-legacy')); -await $`pnpm install`; -await $`pnpm build`; -await $`pnpm test ${cliArguments()}`; diff --git a/scripts/cliff.toml b/scripts/cliff.toml new file mode 100644 index 00000000..62578ee4 --- /dev/null +++ b/scripts/cliff.toml @@ -0,0 +1,58 @@ +# git-cliff configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +header = """ +## What's new +""" +# template for the changelog body +# https://tera.netlify.app/docs +body = """ +{% for group, commits in commits | group_by(attribute="group") %}\ + {% for commit in commits %} + - {{ commit.message | upper_first | split(pat="\n") | first | trim }}\ + {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %}\ + {% endfor %}\ +{% endfor %} +""" +# remove the leading and trailing whitespace from the template +trim = true +footer = """ +""" +postprocessors = [ ] +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = false +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^build\\(deps\\)", skip = true }, + { message = "^build\\(deps-dev\\)", skip = true }, + { message = "^ci", skip = true }, + { body = ".*", group = "Changes" }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" +# regex for skipping tags +skip_tags = "" +# regex for ignoring tags +ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "newest" +# limit the number of commits included in the changelog. +# limit_commits = 42 diff --git a/scripts/client/test-js.mjs b/scripts/js/build.mjs similarity index 67% rename from scripts/client/test-js.mjs rename to scripts/js/build.mjs index 12e1ca92..1294171a 100644 --- a/scripts/client/test-js.mjs +++ b/scripts/js/build.mjs @@ -2,8 +2,9 @@ import 'zx/globals'; import { cliArguments, workingDirectory } from '../utils.mjs'; +const [folder, ...args] = cliArguments(); + // Build the client and run the tests. -cd(path.join(workingDirectory, 'clients', 'js')); +cd(path.join(workingDirectory, folder)); await $`pnpm install`; await $`pnpm build`; -await $`pnpm test ${cliArguments()}`; diff --git a/scripts/client/format-js.mjs b/scripts/js/format.mjs similarity index 56% rename from scripts/client/format-js.mjs rename to scripts/js/format.mjs index dcfc3d4a..87e64843 100644 --- a/scripts/client/format-js.mjs +++ b/scripts/js/format.mjs @@ -2,7 +2,9 @@ import 'zx/globals'; import { cliArguments, workingDirectory } from '../utils.mjs'; +const [folder, ...formatArgs] = cliArguments(); + // Format the client using Prettier. -cd(path.join(workingDirectory, 'clients', 'js')); +cd(path.join(workingDirectory, folder)); await $`pnpm install`; -await $`pnpm format ${cliArguments()}`; +await $`pnpm format ${formatArgs}`; diff --git a/scripts/client/lint-js-legacy.mjs b/scripts/js/lint.mjs similarity index 58% rename from scripts/client/lint-js-legacy.mjs rename to scripts/js/lint.mjs index bfe1357c..a4f25a7a 100644 --- a/scripts/client/lint-js-legacy.mjs +++ b/scripts/js/lint.mjs @@ -2,7 +2,9 @@ import 'zx/globals'; import { cliArguments, workingDirectory } from '../utils.mjs'; +const [folder, ...args] = cliArguments(); + // Check the client using ESLint. -cd(path.join(workingDirectory, 'clients', 'js-legacy')); +cd(path.join(workingDirectory, folder)); await $`pnpm install`; -await $`pnpm lint ${cliArguments()}`; +await $`pnpm lint ${args}`; diff --git a/scripts/client/publish-js-legacy.mjs b/scripts/js/publish.mjs similarity index 77% rename from scripts/client/publish-js-legacy.mjs rename to scripts/js/publish.mjs index d061e487..190fc233 100644 --- a/scripts/client/publish-js-legacy.mjs +++ b/scripts/js/publish.mjs @@ -2,13 +2,13 @@ import 'zx/globals'; import { cliArguments, workingDirectory } from '../utils.mjs'; -const [level, tag = 'latest'] = cliArguments(); +const [level, folder, tag = 'latest'] = cliArguments(); if (!level) { throw new Error('A version level — e.g. "path" — must be provided.'); } // Go to the client directory and install the dependencies. -cd(path.join(workingDirectory, 'clients', 'js-legacy')); +cd(path.join(workingDirectory, folder)); await $`pnpm install`; // Update the version. @@ -29,7 +29,7 @@ if (process.env.CI) { await $`pnpm publish --no-git-checks --tag ${tag}`; // Commit the new version. -await $`git commit -am "Publish JS Legacy client v${newVersion}"`; +await $`git commit -am "Publish ${folder} JS client v${newVersion}"`; // Tag the new version. -await $`git tag -a js-legacy@v${newVersion} -m "JS client v${newVersion}"`; +await $`git tag -a ${folder}-js@v${newVersion} -m "${folder} JS client v${newVersion}"`; diff --git a/scripts/js/test.mjs b/scripts/js/test.mjs new file mode 100644 index 00000000..e9d8e72a --- /dev/null +++ b/scripts/js/test.mjs @@ -0,0 +1,11 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); + +// Build the client and run the tests. +cd(path.join(workingDirectory, folder)); +await $`pnpm install`; +await $`pnpm build`; +await $`pnpm test ${args}`; diff --git a/scripts/program/build.mjs b/scripts/program/build.mjs deleted file mode 100644 index 7a079660..00000000 --- a/scripts/program/build.mjs +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { - cliArguments, - getProgramFolders, - workingDirectory, -} from '../utils.mjs'; - -// Build the programs. -for (const folder of getProgramFolders()) { - const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); - await $`cargo-build-sbf --manifest-path ${manifestPath} ${cliArguments()}`; -} diff --git a/scripts/program/format.mjs b/scripts/program/format.mjs deleted file mode 100644 index c73ddd41..00000000 --- a/scripts/program/format.mjs +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { - cliArguments, - getProgramFolders, - getToolchainArgument, - partitionArguments, - popArgument, - workingDirectory, -} from '../utils.mjs'; - -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const formatArgs = cliArguments(); - -const fix = popArgument(formatArgs, '--fix'); -const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--'); -const toolchain = getToolchainArgument('format'); - -// Format the programs. -for (const folder of getProgramFolders()) { - const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); - - if (fix) { - await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- ${fmtArgs}`; - } else { - await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- --check ${fmtArgs}`; - } -} diff --git a/scripts/program/lint.mjs b/scripts/program/lint.mjs deleted file mode 100644 index e4314314..00000000 --- a/scripts/program/lint.mjs +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { - cliArguments, - getProgramFolders, - getToolchainArgument, - popArgument, - workingDirectory, -} from '../utils.mjs'; - -// Configure arguments here. -const lintArgs = [ - '-Zunstable-options', - '--all-targets', - '--all-features', - '--', - '--deny=warnings', - '--deny=clippy::arithmetic_side_effects', - ...cliArguments(), -]; - -const fix = popArgument(lintArgs, '--fix'); -const toolchain = getToolchainArgument('lint'); - -// Lint the programs using clippy. -for (const folder of getProgramFolders()) { - const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); - - if (fix) { - await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} --fix ${lintArgs}`; - } else { - await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} ${lintArgs}`; - } -} diff --git a/scripts/program/test.mjs b/scripts/program/test.mjs deleted file mode 100644 index fe85dc6e..00000000 --- a/scripts/program/test.mjs +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { - cliArguments, - getProgramFolders, - workingDirectory, -} from '../utils.mjs'; - -const hasSolfmt = await which('solfmt', { nothrow: true }); - -// Test the programs. -for (const folder of getProgramFolders()) { - const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); - - if (hasSolfmt) { - await $`RUST_LOG=error cargo test-sbf --manifest-path ${manifestPath} ${cliArguments()} 2>&1 | solfmt`; - } else { - await $`RUST_LOG=error cargo test-sbf --manifest-path ${manifestPath} ${cliArguments()}`; - } -} diff --git a/scripts/audit-rust.mjs b/scripts/rust/audit.mjs similarity index 96% rename from scripts/audit-rust.mjs rename to scripts/rust/audit.mjs index 1e6beaa5..51f825b7 100644 --- a/scripts/audit-rust.mjs +++ b/scripts/rust/audit.mjs @@ -28,7 +28,7 @@ const advisories = [ // ID: RUSTSEC-2024-0421 // URL: https://rustsec.org/advisories/RUSTSEC-2024-0421 // Solution: Upgrade to >=1.0.0 - // need to solve this depentant tree: + // need to solve this dependency tree: // jsonrpc-core-client v18.0.0 -> jsonrpc-client-transports v18.0.0 -> url v1.7.2 -> idna v0.1.5 'RUSTSEC-2024-0421', ]; diff --git a/scripts/rust/build-sbf.mjs b/scripts/rust/build-sbf.mjs new file mode 100644 index 00000000..64a80d34 --- /dev/null +++ b/scripts/rust/build-sbf.mjs @@ -0,0 +1,10 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { + cliArguments, + workingDirectory, +} from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); +await $`cargo-build-sbf --manifest-path ${manifestPath} ${args}`; diff --git a/scripts/client/format-cli.mjs b/scripts/rust/format.mjs similarity index 63% rename from scripts/client/format-cli.mjs rename to scripts/rust/format.mjs index ae87289c..7e24c575 100644 --- a/scripts/client/format-cli.mjs +++ b/scripts/rust/format.mjs @@ -8,21 +8,14 @@ import { workingDirectory, } from '../utils.mjs'; -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const formatArgs = cliArguments(); +const [folder, ...formatArgs] = cliArguments(); const fix = popArgument(formatArgs, '--fix'); const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--'); -const toolchain = getToolchainArgument('format'); -const manifestPath = path.join( - workingDirectory, - 'clients', - 'cli', - 'Cargo.toml' -); +const toolchain = getToolchainArgument('nightly'); + +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); -// Format the client. if (fix) { await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- ${fmtArgs}`; } else { diff --git a/scripts/rust/hack.mjs b/scripts/rust/hack.mjs new file mode 100644 index 00000000..2e90c7a2 --- /dev/null +++ b/scripts/rust/hack.mjs @@ -0,0 +1,6 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, getToolchainArgument } from '../utils.mjs'; + +const toolchain = getToolchainArgument('nightly'); +await $`cargo ${toolchain} hack check --all-targets --feature-powerset ${cliArguments()}`; diff --git a/scripts/client/lint-cli.mjs b/scripts/rust/lint.mjs similarity index 51% rename from scripts/client/lint-cli.mjs rename to scripts/rust/lint.mjs index 39becd7d..17be05a0 100644 --- a/scripts/client/lint-cli.mjs +++ b/scripts/rust/lint.mjs @@ -7,20 +7,24 @@ import { workingDirectory, } from '../utils.mjs'; -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const lintArgs = cliArguments(); +const [folder, ...args] = cliArguments(); + +// Configure arguments here. +const lintArgs = [ + '-Zunstable-options', + '--all-targets', + '--all-features', + '--', + '--deny=warnings', + '--deny=clippy::arithmetic_side_effects', + ...args, +]; const fix = popArgument(lintArgs, '--fix'); -const toolchain = getToolchainArgument('lint'); -const manifestPath = path.join( - workingDirectory, - 'clients', - 'cli', - 'Cargo.toml' -); +const toolchain = getToolchainArgument('nightly'); + +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); -// Check the client using Clippy. if (fix) { await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} --fix ${lintArgs}`; } else { diff --git a/scripts/rust/publish.mjs b/scripts/rust/publish.mjs new file mode 100644 index 00000000..28bd91b8 --- /dev/null +++ b/scripts/rust/publish.mjs @@ -0,0 +1,41 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, getCargo, workingDirectory } from '../utils.mjs'; + +const dryRun = argv['dry-run'] ?? false; +const [folder, level] = cliArguments(); +if (!folder) { + throw new Error('A path to a directory with a Rust package — e.g. "clients/cli" — must be provided.'); +} +if (!level) { + throw new Error('A version level — e.g. "patch" — must be provided.'); +} + +cd(path.join(workingDirectory, folder)); + +const packageToml = getCargo(folder).package; +const oldVersion = packageToml.version; +const packageName = packageToml.name; +const tagName = path.basename(folder); + +// Publish the new version, commit the repo change, tag it, and push it all. +const releaseArgs = dryRun + ? [] + : ['--tag-name', `${tagName}@v{{version}}`, '--no-confirm', '--execute']; +await $`cargo release ${level} ${releaseArgs}`; + +// Stop here if this is a dry run. +if (dryRun) { + process.exit(0); +} + +// Get the new version. +const newVersion = getCargo(folder).package.version; +const newGitTag = `${tagName}@v${newVersion}`; +const oldGitTag = `${tagName}@v${oldVersion}`; + +// Expose the new version to CI if needed. +if (process.env.CI) { + await $`echo "new_git_tag=${newGitTag}" >> $GITHUB_OUTPUT`; + await $`echo "old_git_tag=${oldGitTag}" >> $GITHUB_OUTPUT`; +} diff --git a/scripts/rust/semver.mjs b/scripts/rust/semver.mjs new file mode 100644 index 00000000..07670ead --- /dev/null +++ b/scripts/rust/semver.mjs @@ -0,0 +1,7 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, getCargo, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); +await $`cargo semver-checks --manifest-path ${manifestPath} ${args}`; diff --git a/scripts/rust/test.mjs b/scripts/rust/test.mjs new file mode 100644 index 00000000..6c5e0f9a --- /dev/null +++ b/scripts/rust/test.mjs @@ -0,0 +1,11 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { + cliArguments, + workingDirectory, +} from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); + +await $`RUST_LOG=error cargo test --manifest-path ${manifestPath} ${args}`;