Prechádzať zdrojové kódy

CI: Add automated publish job (#34)

#### Problem

It's time to publish spl-token that uses all of the component crates to
make downstream users happy, but there's no publish job on the repo.

#### Summary of changes

This PR is as bit of a grab-bag of changes, but they're all to make the
automated publish job work. The changes contained are:

* move semver check job to only run during publish
* update publish script to be generic, copying from the libraries repo
* update testing script to be generic for rust packages by not running
  `cargo test-sbf` and instead doing it by hand, like in token-2022
* rename testing script to `test.mjs`
* remove `test-sbf` feature from spl-token tests
* update solana tools / toolchain versions
Jon C 7 mesiacov pred
rodič
commit
2f189b15e7

+ 7 - 22
.github/workflows/main.yml

@@ -81,26 +81,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
@@ -214,7 +194,7 @@ jobs:
   test_program:
     name: Test Program
     runs-on: ubuntu-latest
-    needs: format_and_lint_program
+    needs: build_program
     steps:
       - name: Git Checkout
         uses: actions/checkout@v4
@@ -223,7 +203,12 @@ jobs:
         uses: ./.github/actions/setup
         with:
           cargo-cache-key: cargo-test-program
-          solana: true
+
+      - name: Restore Program Builds
+        uses: actions/cache/restore@v4
+        with:
+          path: ./**/*.so
+          key: ${{ runner.os }}-builds-${{ github.sha }}
 
       - name: Test
         run: pnpm programs:test

+ 0 - 122
.github/workflows/publish-rust-client.yml

@@ -1,122 +0,0 @@
-name: Publish Rust Client
-
-on:
-  workflow_dispatch:
-    inputs:
-      level:
-        description: Level
-        required: true
-        default: patch
-        type: choice
-        options:
-          - patch
-          - minor
-          - major
-          - rc
-          - beta
-          - alpha
-          - release
-          - version
-      version:
-        description: Version
-        required: false
-        type: string
-      dry_run:
-        description: Dry run
-        required: true
-        default: true
-        type: boolean
-      create_release:
-        description: Create a GitHub release
-        required: true
-        type: boolean
-        default: true
-
-jobs:
-  test_rust:
-    name: Test Rust client
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-rust-client
-          clippy: true
-          rustfmt: true
-          solana: true
-
-      - name: Format Rust Client
-        run: pnpm clients:rust:format
-
-      - name: Lint Rust Client
-        run: pnpm clients:rust:lint
-
-      - name: Test Rust Client
-        run: pnpm clients:rust:test
-
-  publish_rust:
-    name: Publish Rust Client
-    runs-on: ubuntu-latest
-    needs: test_rust
-    permissions:
-      contents: write
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-publish-rust-client
-          cargo-cache-fallback-key: cargo-rust-client
-          clippy: true
-          rustfmt: true
-
-      - 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 == '' }}
-        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 Rust Client
-        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:rust:publish $LEVEL $OPTIONS
-
-      - name: Push Commit and Tag
-        if: github.event.inputs.dry_run != 'true'
-        run: git push origin --follow-tags
-
-      - name: Create GitHub release
-        if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true'
-        uses: ncipollo/release-action@v1
-        with:
-          tag: rust@v${{ steps.publish.outputs.new_version }}

+ 140 - 0
.github/workflows/publish-rust.yml

@@ -0,0 +1,140 @@
+name: Publish Rust Crate
+
+on:
+  workflow_dispatch:
+    inputs:
+      package_path:
+        description: Path to directory with package to release
+        required: true
+        default: 'clients/rust'
+        type: choice
+        options:
+          - clients/rust
+          - interface
+          - program
+          - p-token
+      level:
+        description: Level
+        required: true
+        default: patch
+        type: choice
+        options:
+          - patch
+          - minor
+          - major
+      dry_run:
+        description: Dry run
+        required: true
+        default: true
+        type: boolean
+      create_release:
+        description: Create a GitHub release
+        required: true
+        type: boolean
+        default: true
+
+jobs:
+  test:
+    name: Test Rust Crate
+    runs-on: ubuntu-latest
+    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: Install cargo-audit
+        uses: taiki-e/install-action@v2
+        with:
+          tool: cargo-semver-checks
+
+      - 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 }}"
+
+      - 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:
+      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
+        run: which cargo-release || cargo install cargo-release
+
+      - 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.dry_run }}" == "true" ]; then
+            OPTIONS="--dry-run"
+          else
+            OPTIONS=""
+          fi
+
+          pnpm rust:publish "${{ inputs.package_path }}" "${{ inputs.level }}" $OPTIONS
+
+      - 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: ${{ steps.publish.outputs.new_git_tag }}
+          bodyFile: TEMP_CHANGELOG.md

+ 8 - 3
Cargo.toml

@@ -10,13 +10,18 @@ check-cfg = [
 ]
 
 [workspace.metadata.cli]
-solana = "2.1.0"
+solana = "2.2.0"
 
 # Specify Rust toolchains for rustfmt, clippy, and build.
 # Any unprovided toolchains default to stable.
 [workspace.metadata.toolchains]
-format = "nightly-2024-08-08"
-lint = "nightly-2024-08-08"
+format = "nightly-2024-11-22"
+lint = "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

+ 3 - 3
package.json

@@ -4,7 +4,7 @@
     "programs:build": "zx ./scripts/rust/build-sbf.mjs program",
     "programs:format": "zx ./scripts/rust/format.mjs program",
     "programs:lint": "zx ./scripts/rust/lint.mjs program",
-    "programs:test": "zx ./scripts/rust/test-sbf.mjs program",
+    "programs:test": "zx ./scripts/rust/test.mjs program",
     "solana:check": "zx ./scripts/check-solana-version.mjs",
     "solana:link": "zx ./scripts/link-solana-version.mjs",
     "generate": "pnpm generate:clients",
@@ -18,11 +18,11 @@
     "clients:js:test": "zx ./scripts/js/test.mjs",
     "clients:rust:format": "zx ./scripts/rust/format.mjs clients/rust",
     "clients:rust:lint": "zx ./scripts/rust/lint.mjs clients/rust",
-    "clients:rust:publish": "zx ./scripts/rust/publish.mjs clients/rust",
-    "clients:rust:test": "zx ./scripts/rust/test-sbf.mjs clients/rust",
+    "clients:rust:test": "zx ./scripts/rust/test.mjs clients/rust",
     "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"
   },
   "devDependencies": {

+ 0 - 2
program/tests/assert_instruction_count.rs

@@ -1,5 +1,3 @@
-#![cfg(feature = "test-sbf")]
-
 mod setup;
 
 use {

+ 0 - 2
program/tests/close_account.rs

@@ -1,5 +1,3 @@
-#![cfg(feature = "test-sbf")]
-
 mod setup;
 
 use {

+ 0 - 2
program/tests/processor.rs

@@ -1,5 +1,3 @@
-#![cfg(feature = "test-sbf")]
-
 //! Program state processor tests
 
 use {

+ 0 - 2
program/tests/setup.rs

@@ -1,5 +1,3 @@
-#![cfg(feature = "test-sbf")]
-
 use {
     solana_sdk::{
         account::Account as SolanaAccount, program_pack::Pack, pubkey::Pubkey, rent::Rent,

+ 1 - 1
rust-toolchain.toml

@@ -1,2 +1,2 @@
 [toolchain]
-channel = "1.81.0"
+channel = "1.84.1"

+ 18 - 17
scripts/rust/publish.mjs

@@ -3,18 +3,25 @@ import 'zx/globals';
 import { cliArguments, getCargo, workingDirectory } from '../utils.mjs';
 
 const dryRun = argv['dry-run'] ?? false;
-const [level] = cliArguments();
+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. "path" — must be provided.');
+  throw new Error('A version level — e.g. "patch" — must be provided.');
 }
 
-// Go to the client directory and install the dependencies.
-cd(path.join(workingDirectory, 'clients', 'rust'));
+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.
+// Publish the new version, commit the repo change, tag it, and push it all.
 const releaseArgs = dryRun
   ? []
-  : ['--no-push', '--no-tag', '--no-confirm', '--execute'];
+  : ['--tag-name', `${tagName}@v{{version}}`, '--no-confirm', '--execute'];
 await $`cargo release ${level} ${releaseArgs}`;
 
 // Stop here if this is a dry run.
@@ -23,18 +30,12 @@ if (dryRun) {
 }
 
 // Get the new version.
-const newVersion = getCargo(path.join('clients', 'rust')).package.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_version=${newVersion}" >> $GITHUB_OUTPUT`;
+  await $`echo "new_git_tag=${newGitTag}" >> $GITHUB_OUTPUT`;
+  await $`echo "old_git_tag=${oldGitTag}" >> $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 rust@v${newVersion} -m "Rust client v${newVersion}"`;

+ 2 - 2
scripts/rust/test-sbf.mjs → scripts/rust/test.mjs

@@ -3,6 +3,6 @@ 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 cargo test-sbf --manifest-path ${manifestPath} ${args}`;
+await $`RUST_LOG=error SBF_OUT_DIR=${sbfOutDir} cargo test --manifest-path ${manifestPath} ${args}`;