diff --git a/.cursor/rules/yaml-checklist.mdc b/.cursor/rules/yaml-checklist.mdc new file mode 100644 index 0000000..fda499f --- /dev/null +++ b/.cursor/rules/yaml-checklist.mdc @@ -0,0 +1,21 @@ +--- +globs: *.yml +alwaysApply: false +--- + +Moving stuff to Environment Variables for safer scripting +ex: there is an input named `githubTag`. Add an `ENV:` to it like `INPUTS_GITHUB_TAG: ${{ inputs.githubTag }}` + +### shell scripts + +In github worklows that run shell scripts refer to inputs and outputs via the environment variable convention. +BAD: `RESPONSE=$(npm view .@${{ inputs.githubTag }} version --json --silent || echo "Not published")` +GOOD: `RESPONSE=$(npm view .@$INPUTS_GITHUB_TAG version --json --silent || echo "Not published")` + +### script tag + +when using `script` from actions/github-script +BAD: `script: core.setFailed("The version '$INPUTS_GITHUB_TAG' has already been published to npm")` +GOOD: `script: core.setFailed(`The version '${process.env.INPUTS_GITHUB_TAG}' has already been published to npm`)` + +It's OK to use ${{ foo }} outside of shell script (`run:`) blocks and outside of `script` (example if: statements on a job) diff --git a/.github/actions/npmInstallWithRetries/action.yml b/.github/actions/npmInstallWithRetries/action.yml new file mode 100644 index 0000000..822c729 --- /dev/null +++ b/.github/actions/npmInstallWithRetries/action.yml @@ -0,0 +1,13 @@ +name: npm-install-with-retries +description: 'wraps npm install with retries/timeout to handle network failures' +inputs: + ignore-scripts: + default: 'false' + description: 'Skip pre/post install scripts' +runs: + using: composite + steps: + - name: npm install + uses: salesforcecli/github-workflows/.github/actions/retry@main + with: + command: npm install --timeout 600000 ${{ inputs.ignore-scripts == 'true' && '--ignore-scripts' || '' }} diff --git a/.github/actions/yarnInstallWithRetries/action.yml b/.github/actions/yarnInstallWithRetries/action.yml index c7df369..439f758 100644 --- a/.github/actions/yarnInstallWithRetries/action.yml +++ b/.github/actions/yarnInstallWithRetries/action.yml @@ -1,9 +1,9 @@ name: yarn-install-with-retries -description: "wraps yarn install with retries/timeout to handle network failures" +description: 'wraps yarn install with retries/timeout to handle network failures' inputs: ignore-scripts: default: 'false' - description: "Skip pre/post install scripts" + description: 'Skip pre/post install scripts' runs: using: composite steps: diff --git a/.github/workflows/externalNut.yml b/.github/workflows/externalNut.yml index b86b2de..fef5c02 100644 --- a/.github/workflows/externalNut.yml +++ b/.github/workflows/externalNut.yml @@ -15,18 +15,18 @@ on: inputs: # could we get this from pjson? packageName: - description: "The npm package that this repository publishes. ex: @salesforce/core" + description: 'The npm package that this repository publishes. ex: @salesforce/core' required: true type: string externalProjectGitUrl: - description: "The url that will be cloned. This contains the NUTs you want to run. Ex: https://github.com/salesforcecli/plugin-user" + description: 'The url that will be cloned. This contains the NUTs you want to run. Ex: https://github.com/salesforcecli/plugin-user' type: string required: true command: required: false type: string default: yarn test:nuts - description: "command to execute (ex: yarn test:nuts)" + description: 'command to execute (ex: yarn test:nuts)' nodeVersion: required: false description: version of node to run tests against. Use things like [lts/-1, lts/*, latest] to avoid hardcoding versions @@ -34,31 +34,31 @@ on: default: lts/* os: required: false - description: "runs-on property, ex: ubuntu-latest, windows-latest" + description: 'runs-on property, ex: ubuntu-latest, windows-latest' type: string - default: "ubuntu-latest" + default: 'ubuntu-latest' sfdxExecutablePath: required: false description: "Path to sfdx executable to be used by NUTs, defaults to ''" type: string preBuildCommands: required: false - description: "commands to run before the build...for example, to delete known module conflicts" + description: 'commands to run before the build...for example, to delete known module conflicts' type: string default: 'echo "no preBuildCommands passed"' postBuildCommands: required: false - description: "script to run after the build" + description: 'script to run after the build' type: string default: 'echo "no postBuildCommands passed"' preExternalBuildCommands: required: false - description: "commands to run before the build of the external repo...for example, to delete known module conflicts" + description: 'commands to run before the build of the external repo...for example, to delete known module conflicts' type: string default: 'echo "no preExternalBuildCommands passed"' preSwapCommands: required: false - description: "commands to run before ANY modifications happen. For example, changes that modify the lockfile like yarn add or remove need to happen before the action manually swaps the dependency under test" + description: 'commands to run before ANY modifications happen. For example, changes that modify the lockfile like yarn add or remove need to happen before the action manually swaps the dependency under test' type: string default: 'echo "no preSwapCommands passed"' useCache: @@ -73,10 +73,10 @@ on: required: false description: "branch to clone from the repo. Defaults to 'main'" type: string - default: "main" + default: 'main' ignoreScripts: required: false - description: "if true, will run yarn install --ignore-scripts when building package in node_modules" + description: 'if true, will run yarn install --ignore-scripts when building package in node_modules' type: boolean default: false diff --git a/.github/workflows/npmPublish.yml b/.github/workflows/npmPublish.yml index 7c26d0b..7c1351f 100644 --- a/.github/workflows/npmPublish.yml +++ b/.github/workflows/npmPublish.yml @@ -50,16 +50,29 @@ on: description: the github release tag that you want to publish as an npm package required: true type: string + packageManager: + description: the package manager to use. Defaults to yarn, but can be set to npm + required: false + default: yarn + type: string jobs: check-publish: outputs: published: ${{ steps.is-published.outputs.published }} runs-on: ubuntu-latest + env: + INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} + INPUTS_PACKAGE_MANAGER: ${{ inputs.packageManager }} steps: - uses: actions/checkout@v4 with: ref: ${{ inputs.githubTag }} - + - name: Validate package manager + run: | + if [[ "$INPUTS_PACKAGE_MANAGER" != "yarn" && "$INPUTS_PACKAGE_MANAGER" != "npm" ]]; then + echo "Error: packageManager must be 'yarn' or 'npm', got '$INPUTS_PACKAGE_MANAGER'" + exit 1 + fi - uses: actions/setup-node@v4 with: node-version: ${{ inputs.nodeVersion }} @@ -76,7 +89,6 @@ jobs: echo "published=false" >> "$GITHUB_OUTPUT" fi env: - INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: echo "[INFO] Is package published:\ $STEPS_IS_PUBLISHED_PUBLISHED" @@ -88,8 +100,6 @@ jobs: uses: actions/github-script@v7 with: script: core.setFailed(`The version '${process.env.INPUTS_GITHUB_TAG}' has already been published to npm`) - env: - INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} ctc-open: needs: [check-publish] @@ -103,22 +113,26 @@ jobs: 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 }} + env: + INPUTS_PACKAGE_MANAGER: ${{ inputs.packageManager }} + INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} + INPUTS_TAG: ${{ inputs.tag }} steps: - uses: actions/checkout@v4 with: ref: ${{ inputs.githubTag }} - - uses: actions/setup-node@v4 with: node-version: ${{ inputs.nodeVersion }} - cache: yarn - - - uses: salesforcecli/github-workflows/.github/actions/yarnInstallWithRetries@main - - - run: yarn build - + cache: ${{ inputs.packageManager }} + - name: Install dependencies with yarn + if: inputs.packageManager == 'yarn' + uses: salesforcecli/github-workflows/.github/actions/yarnInstallWithRetries@main + - name: Install dependencies with npm + if: inputs.packageManager == 'npm' + uses: salesforcecli/github-workflows/.github/actions/npmInstallWithRetries@main + - run: $INPUTS_PACKAGE_MANAGER run build - run: npm install -g @salesforce/plugin-release-management - - name: NPM Release run: | sf-release npm:package:release \ @@ -129,8 +143,6 @@ jobs: ${{ inputs.prerelease && format('--prerelease {0}', github.ref_name) || '' }} \ ${{ inputs.sign && '--sign' || '' }} env: - INPUTS_GITHUB_TAG: ${{ inputs.githubTag }} - INPUTS_TAG: ${{ inputs.tag }} NPM_TOKEN: ${{secrets.NPM_TOKEN}} AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} diff --git a/README.md b/README.md index fc1d4b6..bdee275 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,13 @@ jobs: # NPM_TOKEN: ^&*$ ``` +works with npm, too + +```yml +with: + packageManager: npm +``` + ### Plugin Signing Plugins created by Salesforce teams can be signed automatically with `sign:true` if the repo is in [salesforcecli](https://github.com/salesforcecli) or [forcedotcom](https://github.com/forcedotcom) gitub organization. @@ -135,12 +142,12 @@ on: # point at specific branches, or a naming convention via wildcard - prerelease/** tags-ignore: - - "*" + - '*' workflow_dispatch: inputs: prerelease: type: string - description: "Name to use for the prerelease: beta, dev, etc. NOTE: If this is already set in the package.json, it does not need to be passed in here." + description: 'Name to use for the prerelease: beta, dev, etc. NOTE: If this is already set in the package.json, it does not need to be passed in here.' jobs: release: @@ -294,7 +301,7 @@ name: automerge on: workflow_dispatch: schedule: - - cron: "56 2,5,8,11 * * *" + - cron: '56 2,5,8,11 * * *' jobs: automerge: