Browse Source

Add script and CI for publishing Rust clients (#77)

Loris Leiva 1 year ago
parent
commit
0544bdea0e

+ 5 - 0
.changeset/cold-jeans-develop.md

@@ -0,0 +1,5 @@
+---
+"create-solana-program": patch
+---
+
+Add script and CI workflow for publishing Rust clients

+ 128 - 0
template/clients/rust/.github/workflows/publish-rust-client.yml.njk

@@ -0,0 +1,128 @@
+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
+{% if programFramework === 'anchor' %}
+          anchor: true
+{% endif %}
+
+      - name: Format Rust Client
+        run: pnpm clients:rust:format
+
+      - name: Lint Rust Client
+        run: pnpm clients:rust:lint
+
+      - name: Build Programs
+        run: pnpm programs:build
+
+      - 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: {% raw %}${{ secrets.CARGO_REGISTRY_TOKEN }}{% endraw %}
+        if: {% raw %}${{ env.token == '' }}{% endraw %}
+        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: {% raw %}${{ secrets.CARGO_REGISTRY_TOKEN }}{% endraw %}
+        run: |
+          if [ "{% raw %}${{ inputs.level }}{% endraw %}" == "version" ]; then
+            LEVEL={% raw %}${{ inputs.version }}{% endraw %}
+          else
+            LEVEL={% raw %}${{ inputs.level }}{% endraw %}
+          fi
+
+          if [ "{% raw %}${{ inputs.dry_run }}{% endraw %}" == "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: {% raw %}rust@v${{ steps.publish.outputs.new_version }}{% endraw %}

+ 1 - 0
template/clients/rust/package.json

@@ -2,6 +2,7 @@
   "scripts": {
   "scripts": {
     "clients:rust:format": "zx ./scripts/client/format-rust.mjs",
     "clients:rust:format": "zx ./scripts/client/format-rust.mjs",
     "clients:rust:lint": "zx ./scripts/client/lint-rust.mjs",
     "clients:rust:lint": "zx ./scripts/client/lint-rust.mjs",
+    "clients:rust:publish": "zx ./scripts/client/publish-rust.mjs",
     "clients:rust:test": "zx ./scripts/client/test-rust.mjs"
     "clients:rust:test": "zx ./scripts/client/test-rust.mjs"
   },
   },
   "devDependencies": {
   "devDependencies": {

+ 40 - 0
template/clients/rust/scripts/client/publish-rust.mjs

@@ -0,0 +1,40 @@
+#!/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', 'rust')).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 rust@v${newVersion} -m "Rust client v${newVersion}"`;