فهرست منبع

Move from pnpm to Makefile

Moved to Makefile. pnpm stubs retained, since client generation may be added in the future.
Peter Keay 1 ماه پیش
والد
کامیت
68d027d6d7

+ 0 - 103
.github/actions/setup/action.yml

@@ -1,103 +0,0 @@
-name: Setup environment
-
-inputs:
-  cargo-cache-key:
-    description: The key to cache cargo dependencies. Skips cargo caching if not provided.
-    required: false
-  cargo-cache-fallback-key:
-    description: The fallback key to use when caching cargo dependencies. Default to not using a fallback key.
-    required: false
-  cargo-cache-local-key:
-    description: The key to cache local cargo dependencies. Skips local cargo caching if not provided.
-    required: false
-  clippy:
-    description: Install Clippy if `true`. Defaults to `false`.
-    required: false
-  rustfmt:
-    description: Install Rustfmt if `true`. Defaults to `false`.
-    required: false
-  solana:
-    description: Install Solana if `true`. Defaults to `false`.
-    required: false
-
-runs:
-  using: 'composite'
-  steps:
-    - name: Setup pnpm
-      uses: pnpm/action-setup@v3
-
-    - name: Setup Node.js
-      uses: actions/setup-node@v4
-      with:
-        node-version: 20
-        cache: 'pnpm'
-
-    - name: Install Dependencies
-      run: pnpm install --frozen-lockfile
-      shell: bash
-
-    - name: Set Environment Variables
-      shell: bash
-      run: pnpm zx ./scripts/ci/set-env.mjs
-
-    - name: Install Rustfmt
-      if: ${{ inputs.rustfmt == 'true' }}
-      uses: dtolnay/rust-toolchain@master
-      with:
-        toolchain: ${{ env.TOOLCHAIN_FORMAT }}
-        components: rustfmt
-
-    - name: Install Clippy
-      if: ${{ inputs.clippy == 'true' }}
-      uses: dtolnay/rust-toolchain@master
-      with:
-        toolchain: ${{ env.TOOLCHAIN_LINT }}
-        components: clippy
-
-    - name: Install Solana
-      if: ${{ inputs.solana == 'true' }}
-      uses: solana-program/actions/install-solana@v1
-      with:
-        version: ${{ env.SOLANA_VERSION }}
-        cache: true
-
-    - name: Cache Cargo Dependencies
-      if: ${{ inputs.cargo-cache-key && !inputs.cargo-cache-fallback-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-${{ inputs.cargo-cache-key }}
-
-    - name: Cache Cargo Dependencies With Fallback
-      if: ${{ inputs.cargo-cache-key && inputs.cargo-cache-fallback-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-${{ inputs.cargo-cache-key }}
-          ${{ runner.os }}-${{ inputs.cargo-cache-fallback-key }}-${{ hashFiles('**/Cargo.lock') }}
-          ${{ runner.os }}-${{ inputs.cargo-cache-fallback-key }}
-
-    - name: Cache Local Cargo Dependencies
-      if: ${{ inputs.cargo-cache-local-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          .cargo/bin/
-          .cargo/registry/index/
-          .cargo/registry/cache/
-          .cargo/git/db/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-local-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-${{ inputs.cargo-cache-local-key }}

+ 38 - 164
.github/workflows/main.yml

@@ -6,168 +6,42 @@ on:
   pull_request:
     branches: [main]
 
-jobs:
-  format_and_lint_programs:
-    name: Format & Lint Programs
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-
-      - name: Format
-        run: pnpm programs:format
-
-      - name: Lint
-        run: pnpm programs:lint
-
-  format_and_lint_interface:
-    name: Format & Lint Interface
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-
-      - name: Format
-        run: pnpm interface:format
-
-      - name: Lint
-        run: pnpm interface:lint
-
-  format_and_lint_test_harness:
-    name: Format & Lint Test Harness
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-
-      - name: Format
-        run: pnpm test-harness:format
-
-      - name: Lint
-        run: pnpm test-harness:lint
-
-  audit_rust:
-    name: Audit 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-audit
-
-      - name: Install cargo-audit
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-audit
-
-      - name: Run cargo-audit
-        run: pnpm rust:audit
+env:
+  SBPF_PROGRAM_PACKAGES: "['program']"
+  RUST_PACKAGES: "['interface', 'program', 'test_harness']"
+  WASM_PACKAGES: "['interface', 'program']"
 
-  spellcheck_rust:
-    name: Spellcheck 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-spellcheck
-
-      - name: Install cargo-spellcheck
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-spellcheck
-
-      - name: Run cargo-spellcheck
-        run: pnpm rust:spellcheck
-
-  build_programs:
-    name: Build programs
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-programs
-          solana: true
-
-      - name: Build Programs
-        run: pnpm programs:build
-
-      - name: Upload Program Builds
-        uses: actions/upload-artifact@v4
-        with:
-          name: program-builds
-          path: ./target/deploy/*.so
-          if-no-files-found: error
-
-      - name: Save Program Builds For Client Jobs
-        uses: actions/cache/save@v4
-        with:
-          path: ./**/*.so
-          key: ${{ runner.os }}-builds-${{ github.sha }}
-
-  test_programs:
-    name: Test Programs
-    runs-on: ubuntu-latest
-    needs: build_programs
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-program-tests
-          cargo-cache-fallback-key: cargo-programs
-          solana: true
-
-      - name: Restore Program Builds
-        uses: actions/cache/restore@v4
-        with:
-          path: ./**/*.so
-          key: ${{ runner.os }}-builds-${{ github.sha }}
-
-      - name: Test Programs
-        run: pnpm programs:test
-
-  test_interface:
-    name: Test Interface
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-interface
-
-      - name: Test
-        run: pnpm interface:test
+jobs:
+  set_env:
+    name: Set variables to be used in strategy definitions in reusable workflow
+    runs-on: ubuntu-latest
+    outputs:
+      SBPF_PROGRAM_PACKAGES: ${{ steps.compute.outputs.SBPF_PROGRAM_PACKAGES }}
+      RUST_PACKAGES: ${{ steps.compute.outputs.RUST_PACKAGES }}
+      WASM_PACKAGES: ${{ steps.compute.outputs.WASM_PACKAGES }}
+      RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }}
+    steps:
+      - name: Git Checkout
+        uses: actions/checkout@v4
+
+      - name: Compute variables
+        id: compute
+        shell: bash
+        run: |
+          echo "SBPF_PROGRAM_PACKAGES=${{ env.SBPF_PROGRAM_PACKAGES }}" >> $GITHUB_OUTPUT
+          echo "RUST_PACKAGES=${{ env.RUST_PACKAGES }}" >> $GITHUB_OUTPUT 
+          echo "WASM_PACKAGES=${{ env.WASM_PACKAGES }}" >> $GITHUB_OUTPUT
+          echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT"
+          echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT"
+
+  main:
+    needs: set_env
+    uses: solana-program/actions/.github/workflows/main.yml@main
+    with:
+      sbpf-program-packages: ${{ needs.set_env.outputs.SBPF_PROGRAM_PACKAGES }}
+      rust-packages: ${{ needs.set_env.outputs.RUST_PACKAGES }}
+      wasm-packages: ${{ needs.set_env.outputs.WASM_PACKAGES }}
+      rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }}

+ 32 - 133
.github/workflows/publish-rust.yml

@@ -3,7 +3,7 @@ name: Publish Rust Crate
 on:
   workflow_dispatch:
     inputs:
-      package_path:
+      package-path:
         description: Path to directory with package to release
         required: true
         default: 'interface'
@@ -29,151 +29,50 @@ on:
         description: Version (used with level "version")
         required: false
         type: string
-      dry_run:
+      dry-run:
         description: Dry run
         required: true
         default: true
         type: boolean
-      create_release:
+      create-release:
         description: Create a GitHub release
         required: true
         type: boolean
         default: true
 
 jobs:
-  test:
-    name: Test Rust Crate
+  set_env:
+    name: Set variables to be used in strategy definitions
     runs-on: ubuntu-latest
+    outputs:
+      RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }}
+      TARGET: ${{ steps.compute.outputs.TARGET }}
     steps:
       - name: Git Checkout
         uses: actions/checkout@v4
 
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-          solana: true
-          cargo-cache-key: cargo-test-publish-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-test-publish
-
-      - name: Format
-        run: pnpm zx ./scripts/rust/format.mjs "${{ inputs.package_path }}"
-
-      - name: Lint
-        run: pnpm zx ./scripts/rust/lint.mjs "${{ inputs.package_path }}"
-
-      - name: Build programs
-        run: pnpm programs:build
-
-      - name: Test
-        run: pnpm zx ./scripts/rust/test.mjs "${{ inputs.package_path }}"
-
-  semver:
-    name: Check Semver
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-publish-semver-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-publish-semver
-
-      - name: Install cargo-semver-checks
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-semver-checks@0.42.0,cargo-release@0.25.18
-
-      - name: Set Git Author (required for cargo-release)
-        run: |
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git config --global user.name "github-actions[bot]"
-
-      - name: Set Version
+      - name: Compute variables
+        id: compute
+        shell: bash
         run: |
-          if [ "${{ inputs.level }}" == "version" ]; then
-            LEVEL=${{ inputs.version }}
-          else
-            LEVEL=${{ inputs.level }}
-          fi
-          cargo release $LEVEL --manifest-path "${{ inputs.package_path }}/Cargo.toml" --no-tag --no-publish --no-push --no-confirm --execute
-
-      - name: Check semver
-        run: pnpm rust:semver --manifest-path "${{ inputs.package_path }}/Cargo.toml"
-
-  publish:
-    name: Publish Rust Crate
-    runs-on: ubuntu-latest
-    needs: [test, semver]
-    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
-        with:
-          cargo-cache-key: cargo-publish-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-publish
-
-      - name: Install cargo-release
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-release@0.25.18
-
-      - name: Ensure CARGO_REGISTRY_TOKEN variable is set
-        env:
-          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\"."
-          exit 1
-
-      - name: Set Git Author
-        run: |
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git config --global user.name "github-actions[bot]"
-
-      - 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 rust:publish "${{ inputs.package_path }}" $LEVEL $OPTIONS
-
-      - name: Generate a changelog
-        if: github.event.inputs.create_release == 'true'
-        uses: orhun/git-cliff-action@v4
-        with:
-          config: "scripts/cliff.toml"
-          args: ${{ steps.publish.outputs.old_git_tag }}..HEAD --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: ${{ steps.publish.outputs.new_git_tag }}
-          bodyFile: TEMP_CHANGELOG.md
+          echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT"
+          echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT"
+          TARGET=$(echo ${{ inputs.package-path }} | sed 's#/#-#')
+          echo "TARGET=$TARGET" >> "$GITHUB_OUTPUT"
+
+  main:
+    needs: set_env
+    uses: solana-program/actions/.github/workflows/publish-rust.yml@main
+    with:
+      sbpf-program-packages: "program"
+      solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }}
+      clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      target: ${{ needs.set_env.outputs.TARGET }}
+      package-path: ${{ inputs.package-path }}
+      level: ${{ inputs.level }}
+      version: ${{ inputs.version }}
+      create-release: ${{ inputs.create-release }}
+      dry-run: ${{ inputs.dry-run }}
+    secrets: inherit

+ 6 - 1
Cargo.toml

@@ -1,6 +1,6 @@
 [workspace]
 resolver = "2"
-members = ["interface", "program", "test-harness"]
+members = ["interface", "program", "test_harness"]
 
 [workspace.metadata.cli]
 solana = "3.0.0"
@@ -13,3 +13,8 @@ lint = "nightly-2025-02-16"
 
 [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

+ 98 - 0
Makefile

@@ -0,0 +1,98 @@
+RUST_TOOLCHAIN_NIGHTLY = nightly-2025-02-16
+SOLANA_CLI_VERSION = 3.0.0
+
+nightly = +${RUST_TOOLCHAIN_NIGHTLY}
+
+# This is a bit tricky -- findstring returns the found string, so we're looking
+# for "directory-", returning that, and replacing "-" with "/" to change the
+# first "-" to a "/". But if it isn't found, we replace "" with "", which works
+# in the case where there is no subdirectory.
+pattern-dir = $(firstword $(subst -, ,$1))
+find-pattern-dir = $(findstring $(call pattern-dir,$1)-,$1)
+make-path = $(subst $(call find-pattern-dir,$1),$(subst -,/,$(call find-pattern-dir,$1)),$1)
+
+rust-toolchain-nightly:
+	@echo ${RUST_TOOLCHAIN_NIGHTLY}
+
+solana-cli-version:
+	@echo ${SOLANA_CLI_VERSION}
+
+cargo-nightly:
+	cargo $(nightly) $(ARGS)
+
+generate-clients:
+	@echo "No JavaScript clients to generate"
+
+audit:
+	cargo audit \
+			--ignore RUSTSEC-2022-0093 \
+			--ignore RUSTSEC-2024-0344 \
+			--ignore RUSTSEC-2024-0376 $(ARGS)
+
+spellcheck:
+	cargo spellcheck --code 1 $(ARGS)
+
+clippy-%:
+	cargo $(nightly) clippy --manifest-path $(call make-path,$*)/Cargo.toml \
+	  --all-targets \
+	  --all-features \
+		-- \
+		--deny=warnings \
+		--deny=clippy::default_trait_access \
+		--deny=clippy::arithmetic_side_effects \
+		--deny=clippy::manual_let_else \
+		--deny=clippy::used_underscore_binding $(ARGS)
+
+format-check-%:
+	cargo $(nightly) fmt --check --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+powerset-%:
+	cargo $(nightly) hack check --feature-powerset --all-targets --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+semver-check-%:
+	cargo semver-checks --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+shellcheck:
+	git ls-files -- '*.sh' | xargs shellcheck --color=always --external-sources --shell=bash $(ARGS)
+
+sort-check:
+	cargo $(nightly) sort --workspace --check $(ARGS)
+
+bench-%:
+	cargo $(nightly) bench --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+regression-%:
+	mollusk run-test --proto mollusk --ignore-compute-units $(call make-path,$*)/fuzz/program-mb.so ./target/deploy/$(subst -,_,$(shell toml get $(call make-path,$*)/Cargo.toml package.name)).so $(call make-path,$*)/fuzz/blob $(shell toml get $(call make-path,$*)/Cargo.toml package.metadata.solana.program-id)
+
+format-rust:
+	cargo $(nightly) fmt --all $(ARGS)
+
+build-sbf-%:
+	cargo build-sbf --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+build-wasm-%:
+	cargo build --target wasm32-unknown-unknown --manifest-path $(call make-path,$*)/Cargo.toml --all-features $(ARGS)
+
+build-doc-%:
+	RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo $(nightly) doc --all-features --no-deps --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+test-doc-%:
+	cargo $(nightly) test --doc --all-features --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+test-%:
+	SBF_OUT_DIR=$(PWD)/target/deploy cargo $(nightly) test --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+# Helpers for publishing
+tag-name = $(lastword $(subst /, ,$(call make-path,$1)))
+preid-arg = $(subst pre,--preid $2,$(findstring pre,$1))
+package-version = $(subst ",,$(shell jq -r '.version' $(call make-path,$1)/package.json))
+crate-version = $(subst ",,$(shell toml get $(call make-path,$1)/Cargo.toml package.version))
+
+git-tag-rust-%:
+	@echo "$(call tag-name,$*)@v$(call crate-version,$*)"
+
+publish-rust-%:
+	cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}" --execute --no-confirm --dependent-version fix
+
+publish-rust-dry-run-%:
+	cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}"

+ 2 - 26
package.json

@@ -1,29 +1,5 @@
 {
+  "name": "spl-associated-token-account",
   "private": true,
-  "scripts": {
-    "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",
-    "interface:test": "zx ./scripts/rust/test.mjs interface",
-    "interface:format": "zx ./scripts/rust/format.mjs interface",
-    "interface:lint": "zx ./scripts/rust/lint.mjs interface",
-    "template:upgrade": "zx ./scripts/upgrade-template.mjs",
-    "rust:spellcheck": "cargo spellcheck --code 1",
-    "rust:audit": "zx ./scripts/rust/audit.mjs",
-    "rust:publish": "zx ./scripts/rust/publish.mjs",
-    "rust:semver": "cargo semver-checks",
-    "test-harness:format": "zx ./scripts/rust/format.mjs test-harness",
-    "test-harness:lint": "zx ./scripts/rust/lint.mjs test-harness",
-    "test-harness:test": "zx ./scripts/rust/test.mjs test-harness"
-  },
-  "devDependencies": {
-    "@iarna/toml": "^2.2.5",
-    "typescript": "^5.9.3",
-    "zx": "^8.8.4"
-  },
-  "engines": {
-    "node": ">=v20.0.0"
-  },
-  "packageManager": "pnpm@9.1.0"
+  "packageManager": "pnpm@9.15.4"
 }

+ 1 - 34
pnpm-lock.yaml

@@ -6,37 +6,4 @@ settings:
 
 importers:
 
-  .:
-    devDependencies:
-      '@iarna/toml':
-        specifier: ^2.2.5
-        version: 2.2.5
-      typescript:
-        specifier: ^5.9.3
-        version: 5.9.3
-      zx:
-        specifier: ^8.8.4
-        version: 8.8.4
-
-packages:
-
-  '@iarna/toml@2.2.5':
-    resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
-
-  typescript@5.9.3:
-    resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-
-  zx@8.8.4:
-    resolution: {integrity: sha512-44GcD+ZlM/v1OQtbwnSxLPcoE1ZEUICmR+RSbJZLAqfIixNLuMjLyh0DcS75OyfJ/sWYAwCWDmDvJ4hdnANAPQ==}
-    engines: {node: '>= 12.17.0'}
-    hasBin: true
-
-snapshots:
-
-  '@iarna/toml@2.2.5': {}
-
-  typescript@5.9.3: {}
-
-  zx@8.8.4: {}
+  .: {}

+ 1 - 1
program/Cargo.toml

@@ -26,7 +26,7 @@ spl-token-2022-interface = "2.0.0"
 thiserror = "2.0"
 
 [dev-dependencies]
-ata-mollusk-harness = { version = "1.0.0", path = "../test-harness" }
+ata-mollusk-harness = { version = "1.0.0", path = "../test_harness" }
 mollusk-svm = { version = "0.6.3" }
 solana-instruction = "3.0"
 solana-keypair = "3.0"

+ 0 - 6
scripts/ci/set-env.mjs

@@ -1,6 +0,0 @@
-#!/usr/bin/env zx
-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`;

+ 58 - 0
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

+ 0 - 31
scripts/rust/audit.mjs

@@ -1,31 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-
-const advisories = [
-  // ed25519-dalek: Double Public Key Signing Function Oracle Attack
-  //
-  // Remove once repo upgrades to ed25519-dalek v2
-  'RUSTSEC-2022-0093',
-
-  // curve25519-dalek
-  //
-  // Remove once repo upgrades to curve25519-dalek v4
-  'RUSTSEC-2024-0344',
-
-  // Crate:     tonic
-  // Version:   0.9.2
-  // Title:     Remotely exploitable Denial of Service in Tonic
-  // Date:      2024-10-01
-  // ID:        RUSTSEC-2024-0376
-  // URL:       https://rustsec.org/advisories/RUSTSEC-2024-0376
-  // Solution:  Upgrade to >=0.12.3
-  'RUSTSEC-2024-0376',
-];
-const ignores = []
-advisories.forEach(x => {
-  ignores.push('--ignore');
-  ignores.push(x);
-});
-
-// Check Solana version.
-await $`cargo audit ${ignores}`;

+ 0 - 10
scripts/rust/build-sbf.mjs

@@ -1,10 +0,0 @@
-#!/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}`;

+ 0 - 23
scripts/rust/format.mjs

@@ -1,23 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  getToolchainArgument,
-  partitionArguments,
-  popArgument,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...formatArgs] = cliArguments();
-
-const fix = popArgument(formatArgs, '--fix');
-const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--');
-const toolchain = getToolchainArgument('format');
-
-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}`;
-}

+ 0 - 32
scripts/rust/lint.mjs

@@ -1,32 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  getToolchainArgument,
-  popArgument,
-  workingDirectory,
-} from '../utils.mjs';
-
-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, folder, 'Cargo.toml');
-
-if (fix) {
-  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} --fix ${lintArgs}`;
-} else {
-  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} ${lintArgs}`;
-}

+ 0 - 41
scripts/rust/publish.mjs

@@ -1,41 +0,0 @@
-#!/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`;
-}

+ 0 - 8
scripts/rust/test.mjs

@@ -1,8 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { cliArguments, workingDirectory } from '../utils.mjs';
-
-const [folder, ...args] = cliArguments();
-const sbfOutDir = path.join(workingDirectory, 'target', 'deploy');
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-await $`RUST_LOG=error SBF_OUT_DIR=${sbfOutDir} cargo test --manifest-path ${manifestPath} ${args}`;

+ 0 - 58
scripts/upgrade-template.mjs

@@ -1,58 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { getCargo } from './utils.mjs';
-
-// Arguments to pass to the `create-solana-program` command.
-const rustClientCargo = getCargo(path.join('clients', 'rust'));
-const jsClientPkg = require(
-  path.join(__dirname, '..', 'clients', 'js', 'package.json')
-);
-const templateArgs = [
-  'memo',
-  '--address',
-  'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr',
-  '--org',
-  'solana-program',
-  '--rust-client-crate-name',
-  rustClientCargo.package.name,
-  '--js-client-package-name',
-  jsClientPkg.name,
-  '--default',
-  '--force',
-];
-
-// File and folder patterns that should not be overwritten by the template upgrade.
-const unchangedGlobs = [
-  'clients/**/src/**',
-  'clients/**/src/*',
-  'clients/js/test/*',
-  'clients/rust/tests/*',
-  'program/**/*',
-  'program/*',
-  'scripts/generate-clients.mjs',
-  'scripts/generate-idls.mjs',
-  'scripts/upgrade-template.mjs',
-  'scripts/program/*',
-  'Cargo.lock',
-  '**/pnpm-lock.yaml',
-  'pnpm-lock.yaml',
-];
-
-// Prevent CLI arguments from being escaped.
-$.quote = (command) => command;
-
-// Re-generate the repo from the parent directory.
-cd('..');
-await $`pnpm create solana-program@latest ${templateArgs}`;
-
-// Go back inside the updated repo.
-cd('memo');
-
-// Restore files and folders that should not be overwritten.
-await $`git add --all`;
-for (const glob of unchangedGlobs) {
-  await $`git restore --worktree --staged "${glob}"`;
-}
-
-// Re-install dependencies.
-await $`pnpm install`;

+ 0 - 127
scripts/utils.mjs

@@ -1,127 +0,0 @@
-import 'zx/globals';
-import { parse as parseToml } from '@iarna/toml';
-
-$.verbose = true;
-process.env.FORCE_COLOR = 3;
-process.env.CARGO_TERM_COLOR = 'always';
-
-export const workingDirectory = (await $`pwd`.quiet()).toString().trim();
-
-export function getAllProgramIdls() {
-  return getAllProgramFolders().map((folder) =>
-    path.join(workingDirectory, folder, 'idl.json')
-  );
-}
-
-export function getExternalProgramOutputDir() {
-  const config = getCargoMetadata()?.solana?.['external-programs-output'];
-  return path.join(workingDirectory, config ?? 'target/deploy');
-}
-
-export function getExternalProgramAddresses() {
-  const addresses = getProgramFolders().flatMap(
-    (folder) => getCargoMetadata(folder)?.solana?.['program-dependencies'] ?? []
-  );
-  return Array.from(new Set(addresses));
-}
-
-export function getExternalAccountAddresses() {
-  const addresses = getProgramFolders().flatMap(
-    (folder) => getCargoMetadata(folder)?.solana?.['account-dependencies'] ?? []
-  );
-  return Array.from(new Set(addresses));
-}
-
-let didWarnAboutMissingPrograms = false;
-export function getProgramFolders() {
-  let programs;
-
-  if (process.env.PROGRAMS) {
-    try {
-      programs = JSON.parse(process.env.PROGRAMS);
-    } catch (error) {
-      programs = process.env.PROGRAMS.split(/\s+/);
-    }
-  } else {
-    programs = getAllProgramFolders();
-  }
-
-  const filteredPrograms = programs.filter((program) =>
-    fs.existsSync(path.join(workingDirectory, program))
-  );
-
-  if (
-    filteredPrograms.length !== programs.length &&
-    !didWarnAboutMissingPrograms
-  ) {
-    didWarnAboutMissingPrograms = true;
-    programs
-      .filter((program) => !filteredPrograms.includes(program))
-      .forEach((program) => {
-        echo(chalk.yellow(`Program not found: ${workingDirectory}/${program}`));
-      });
-  }
-
-  return filteredPrograms;
-}
-
-export function getAllProgramFolders() {
-  return getCargo().workspace.members.filter((member) =>
-    (getCargo(member).lib?.['crate-type'] ?? []).includes('cdylib')
-  );
-}
-
-export function getCargo(folder) {
-  return parseToml(
-    fs.readFileSync(
-      path.join(workingDirectory, folder ? folder : '.', 'Cargo.toml'),
-      'utf8'
-    )
-  );
-}
-
-export function getCargoMetadata(folder) {
-  const cargo = getCargo(folder);
-  return folder ? cargo?.package?.metadata : cargo?.workspace?.metadata;
-}
-
-export function getSolanaVersion() {
-  return getCargoMetadata()?.cli?.solana;
-}
-
-export function getToolchain(operation) {
-  return getCargoMetadata()?.toolchains?.[operation];
-}
-
-export function getToolchainArgument(operation) {
-  const channel = getToolchain(operation);
-  return channel ? `+${channel}` : '';
-}
-
-export function cliArguments() {
-  return process.argv.slice(3);
-}
-
-export function popArgument(args, arg) {
-  const index = args.indexOf(arg);
-  if (index >= 0) {
-    args.splice(index, 1);
-  }
-  return index >= 0;
-}
-
-export function partitionArguments(args, delimiter) {
-  const index = args.indexOf(delimiter);
-  return index >= 0
-    ? [args.slice(0, index), args.slice(index + 1)]
-    : [args, []];
-}
-
-export async function getInstalledSolanaVersion() {
-  try {
-    const { stdout } = await $`solana --version`.quiet();
-    return stdout.match(/(\d+\.\d+\.\d+)/)?.[1];
-  } catch (error) {
-    return '';
-  }
-}

+ 0 - 0
test-harness/Cargo.toml → test_harness/Cargo.toml


+ 0 - 0
test-harness/src/lib.rs → test_harness/src/lib.rs