diff --git a/.github/workflows/publish-js-client.yml b/.github/workflows/publish-js-client.yml new file mode 100644 index 0000000..768c686 --- /dev/null +++ b/.github/workflows/publish-js-client.yml @@ -0,0 +1,146 @@ +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 + default: patch + type: choice + options: + - patch + - minor + - major + - prerelease + - prepatch + - preminor + - premajor + tag: + description: NPM Tag (and preid for pre-releases) + required: true + type: string + default: latest + create_release: + description: Create a GitHub release + required: true + type: boolean + default: true + +jobs: + test: + name: Test JS package + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + 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: Lint + run: pnpm zx ./scripts/js/lint.mjs "${{ inputs.package_path }}" + + - name: Build Record + run: pnpm programs:build + + - name: Test + run: pnpm zx ./scripts/js/test.mjs "${{ inputs.package_path }}" + + publish: + name: Publish JS package + 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 + + - 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.SOLANA_PROGRAM_NPM_TOKEN }} + if: ${{ env.token == '' }} + run: | + 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 + env: + 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: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Publish JS Client + id: publish + 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: ${{ steps.publish.outputs.new_git_tag }} + bodyFile: TEMP_CHANGELOG.md diff --git a/clients/js-legacy/package.json b/clients/js-legacy/package.json index 966522a..e4acc80 100644 --- a/clients/js-legacy/package.json +++ b/clients/js-legacy/package.json @@ -13,6 +13,7 @@ "src" ], "scripts": { + "prepublishOnly": "pnpm build", "build": "tsc --build --verbose", "lint": "eslint --max-warnings 0 .", "lint:fix": "eslint --fix .", diff --git a/scripts/js/publish.mjs b/scripts/js/publish.mjs new file mode 100644 index 0000000..ace9ce4 --- /dev/null +++ b/scripts/js/publish.mjs @@ -0,0 +1,45 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, getPackageJson, workingDirectory } from '../utils.mjs'; + +const [folder, level, tag = 'latest'] = cliArguments(); +if (!folder) { + throw new Error('A path to a directory with a JS package — e.g. "clients/js" — must be provided.'); +} +if (!level) { + 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, folder)); +await $`pnpm install`; + +const tagName = path.basename(folder); +const packageJson = getPackageJson(folder); +const oldVersion = packageJson.version; +const oldGitTag = `${tagName}@v${oldVersion}`; + +// 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(); +const newGitTag = `${tagName}@v${newVersion}`; + +// 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`; +} + +// 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 ${tagName} v${newVersion}"`; + +// Tag the new version. +await $`git tag -a ${newGitTag} -m "${tagName} v${newVersion}"`;