Support NPM option for release workflow & allow publishing to private GitHub repos. #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| on: | ||
| workflow_call: | ||
| secrets: | ||
| NPM_TOKEN: | ||
| description: npm token | ||
| AWS_ACCESS_KEY_ID: | ||
| description: AWS access key id. Only required if sign = true | ||
| AWS_SECRET_ACCESS_KEY: | ||
| description: AWS secret access key. Only required if sign = true | ||
| SVC_CLI_BOT_GITHUB_TOKEN: | ||
| description: GitHub token for package publishing. Required if publishToGithubPackages is true | ||
| required: false | ||
| inputs: | ||
| tag: | ||
| required: false | ||
| description: tag used to publish to npm | ||
| default: latest | ||
| type: string | ||
| sign: | ||
| required: false | ||
| description: signs the package using sf-release if set to true | ||
| default: false | ||
| type: boolean | ||
| dryrun: | ||
| required: false | ||
| description: if true, the job will run but will not publish to npm or push to git | ||
| default: false | ||
| type: boolean | ||
| prerelease: | ||
| required: false | ||
| description: if true, it will use the version <version>-<branch>.0 | ||
| type: boolean | ||
| default: false | ||
| nodeVersion: | ||
| description: version of node to use. It's better to specify latest, lts/* or lts/-1 than to hardode numbers | ||
| type: string | ||
| default: lts/* | ||
| required: false | ||
| ctc: | ||
| description: | | ||
| Use CTC. Requires environment to contain | ||
| SF_CHANGE_CASE_SFDX_AUTH_URL, SF_CHANGE_CASE_TEMPLATE_ID, SF_CHANGE_CASE_CONFIGURATION_ITEM. | ||
| Also requires a static ip runner (you can't use ubuntu-latest) | ||
| type: boolean | ||
| required: false | ||
| runsOn: | ||
| description: the runner. Only needed if you need a non-public runner (ex, for git checkout from IP restricted private repo) | ||
| default: ubuntu-latest | ||
| required: false | ||
| type: string | ||
| githubTag: | ||
| description: the github release tag that you want to publish as an npm package | ||
| required: true | ||
| type: string | ||
| package-manager: | ||
| type: string | ||
| description: "Package manager to use (npm or yarn)" | ||
| default: "yarn" | ||
| required: false | ||
| publishToGithubPackages: | ||
| type: boolean | ||
| description: "If true, publish to GitHub Packages instead of npm" | ||
| default: false | ||
| required: false | ||
| scope: | ||
| type: string | ||
| description: "Scope for the package (e.g., @organization). Required if publishToGithubPackages is true" | ||
| required: false | ||
| actions-repository: | ||
| type: string | ||
| description: "The repository owner/name to use for actions (format: owner/repo)" | ||
| default: "salesforcecli/github-workflows" | ||
| required: false | ||
| actions-ref: | ||
| type: string | ||
| description: "The branch, tag or SHA to use for actions" | ||
| default: "main" | ||
| required: false | ||
| jobs: | ||
| check-publish: | ||
| outputs: | ||
| published: ${{ steps.is-published.outputs.published }} | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: read | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ inputs.githubTag }} | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ inputs.nodeVersion }} | ||
| registry-url: ${{ inputs.publishToGithubPackages && 'https://npm.pkg.github.com' || '' }} | ||
| scope: ${{ inputs.scope }} | ||
| - name: Is published | ||
| id: is-published | ||
| run: | | ||
| if [ "$INPUTS_PUBLISH_TO_GITHUB_PACKAGES" = "true" ]; then | ||
| # For GitHub Packages, check if the package exists in the registry | ||
| RESPONSE=$(npm view $INPUTS_SCOPE/$GITHUB_REPOSITORY_NAME@$INPUTS_GITHUB_TAG version --json --silent || echo "Not published") | ||
| else | ||
| # For npm, check if the package exists in the npm registry | ||
| RESPONSE=$(npm view .@$INPUTS_GITHUB_TAG version --json --silent || echo "Not published") | ||
| fi | ||
| # The response is wrapped in double quotes, so we need to compare it with (escaped) quotes | ||
| if [ "$RESPONSE" = "\"$INPUTS_GITHUB_TAG\"" ]; then | ||
| echo "published=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "published=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| env: | ||
| INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} | ||
| INPUTS_PUBLISH_TO_GITHUB_PACKAGES: ${{ inputs.publishToGithubPackages }} | ||
| INPUTS_SCOPE: ${{ inputs.scope }} | ||
| GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }} | ||
| NODE_AUTH_TOKEN: ${{ inputs.publishToGithubPackages && secrets.SVC_CLI_BOT_GITHUB_TOKEN || secrets.NPM_TOKEN }} | ||
| - run: echo "[INFO] Is package published:\ $STEPS_IS_PUBLISHED_PUBLISHED" | ||
| env: | ||
| STEPS_IS_PUBLISHED_PUBLISHED: ${{ steps.is-published.outputs.published }} | ||
| - name: Fail if published | ||
| if: steps.is-published.outputs.published == 'true' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const message = 'The version \'' + process.env.INPUTS_GITHUB_TAG + '\' has already been published to ' + | ||
| (process.env.INPUTS_PUBLISH_TO_GITHUB_PACKAGES === 'true' ? 'GitHub Packages' : 'npm'); | ||
| core.setFailed(message); | ||
| env: | ||
| INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} | ||
| INPUTS_PUBLISH_TO_GITHUB_PACKAGES: ${{ inputs.publishToGithubPackages }} | ||
| ctc-open: | ||
| needs: [check-publish] | ||
| if: inputs.ctc && needs.check-publish.outputs.published == 'false' | ||
| uses: ${{ inputs.actions-repository }}/.github/workflows/ctcOpen.yml@${{ inputs.actions-ref }} | ||
| secrets: inherit | ||
| with: | ||
| actions-repository: ${{ inputs.actions-repository }} | ||
| actions-ref: ${{ inputs.actions-ref }} | ||
| npm-publish: | ||
| needs: [check-publish, ctc-open] | ||
| if: ${{ always() && needs.check-publish.outputs.published == 'false' && (!inputs.ctc || (inputs.ctc && needs.ctc-open.outputs.changeCaseId)) }} | ||
| runs-on: ${{ inputs.runsOn }} | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| steps: | ||
| - name: Validate inputs | ||
| if: inputs.publishToGithubPackages == 'true' | ||
| run: | | ||
| if [ -z "$INPUTS_SCOPE" ]; then | ||
| echo "Error: scope is required when publishing to GitHub Packages" | ||
| exit 1 | ||
| fi | ||
| env: | ||
| INPUTS_SCOPE: ${{ inputs.scope }} | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ inputs.githubTag }} | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ inputs.nodeVersion }} | ||
| cache: ${{ inputs.package-manager }} | ||
| registry-url: ${{ inputs.publishToGithubPackages && 'https://npm.pkg.github.com' || '' }} | ||
| scope: ${{ inputs.scope }} | ||
| - uses: ${{ inputs.actions-repository }}/.github/actions/yarnInstallWithRetries@${{ inputs.actions-ref }} | ||
| if: inputs.package-manager == 'yarn' | ||
| - name: npm install | ||
| if: inputs.package-manager == 'npm' | ||
| run: npm ci | ||
| - name: Build | ||
| run: ${{ inputs.package-manager }} build | ||
| - run: npm install -g @salesforce/plugin-release-management | ||
| - name: NPM Release | ||
| run: | | ||
| sf-release npm:package:release \ | ||
| --githubtag "$INPUTS_GITHUB_TAG" \ | ||
| --npmtag "$INPUTS_TAG" \ | ||
| --no-install \ | ||
| ${{ inputs.dryrun && '--dryrun' || '' }} \ | ||
| ${{ inputs.prerelease && format('--prerelease {0}', github.ref_name) || '' }} \ | ||
| ${{ inputs.sign && '--sign' || '' }} | ||
| env: | ||
| INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} | ||
| INPUTS_TAG: ${{ inputs.tag }} | ||
| NPM_TOKEN: ${{ inputs.publishToGithubPackages && secrets.SVC_CLI_BOT_GITHUB_TOKEN || secrets.NPM_TOKEN }} | ||
| AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} | ||
| AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} | ||
| ctcCloseSuccess: | ||
| needs: [ctc-open, npm-publish] | ||
| if: needs.ctc-open.result == 'success' && needs.npm-publish.result == 'success' && needs.ctc-open.outputs.changeCaseId | ||
| uses: ${{ inputs.actions-repository }}/.github/workflows/ctcClose.yml@${{ inputs.actions-ref }} | ||
| secrets: inherit | ||
| with: | ||
| changeCaseId: ${{needs.ctc-open.outputs.changeCaseId}} | ||
| actions-repository: ${{ inputs.actions-repository }} | ||
| actions-ref: ${{ inputs.actions-ref }} | ||
| ctcCloseFail: | ||
| needs: [ctc-open, npm-publish] | ||
| if: always() && inputs.ctc && needs.ctc-open.outputs.changeCaseId && (needs.ctc-open.result != 'success' || needs.npm-publish.result != 'success') | ||
| uses: ${{ inputs.actions-repository }}/.github/workflows/ctcClose.yml@${{ inputs.actions-ref }} | ||
| secrets: inherit | ||
| with: | ||
| changeCaseId: ${{ needs.ctc-open.outputs.changeCaseId }} | ||
| status: Not Implemented | ||
| actions-repository: ${{ inputs.actions-repository }} | ||
| actions-ref: ${{ inputs.actions-ref }} | ||