mirror of
https://github.com/lukaszraczylo/shared-actions.git
synced 2026-10-12 04:54:48 +00:00
Co-authored-by: tozuo-home-cluster-eso[bot] <287217661+tozuo-home-cluster-eso[bot]@users.noreply.github.com>
176 lines
6.5 KiB
YAML
176 lines
6.5 KiB
YAML
name: Node Pull Request
|
|
|
|
# Checks for a Node, Vue or Astro project: install without touching the lockfile,
|
|
# then run lint, typecheck, test and build. A script that does not exist is skipped.
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
node-version:
|
|
description: "Node.js version to use"
|
|
required: false
|
|
type: string
|
|
default: "22"
|
|
working-directory:
|
|
description: "Directory that holds package.json"
|
|
required: false
|
|
type: string
|
|
default: "."
|
|
scripts:
|
|
description: "Comma-separated package.json scripts to run, in order. A script that does not exist is skipped."
|
|
required: false
|
|
type: string
|
|
default: "lint,typecheck,test,build"
|
|
pnpm-version:
|
|
description: "pnpm version to use, for a repo whose package.json has no packageManager field. Empty uses the packageManager field, or the newest pnpm."
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
require-tests:
|
|
description: "Fail when package.json has no test script"
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
lfs:
|
|
description: "Enable Git LFS checkout (for repos with large files)"
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
runner:
|
|
description: "Runner label, or JSON object such as {\"group\":\"ci\",\"labels\":[\"linux\"]} to select a runner group. Falls back to vars.SHARED_ACTIONS_RUNNER, then ubuntu-latest."
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
|
|
concurrency:
|
|
group: node-pr-${{ github.repository }}-${{ github.event_name }}-${{ github.head_ref || github.ref_name }}-${{ inputs.working-directory }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
pre:
|
|
name: Detect duplicate run
|
|
runs-on: ${{ fromJSON(startsWith(inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest', '{') && (inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest') || format('"{0}"', inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest')) }}
|
|
timeout-minutes: 5
|
|
permissions:
|
|
pull-requests: read
|
|
outputs:
|
|
skip: ${{ steps.dup.outputs.skip }}
|
|
steps:
|
|
# A push to a branch with an open PR also fires pull_request; run only the PR one.
|
|
- name: Skip push run when a PR is open
|
|
id: dup
|
|
uses: actions/github-script@v9
|
|
with:
|
|
script: |
|
|
let skip = false;
|
|
if (context.eventName === 'push') {
|
|
try {
|
|
const { data } = await github.rest.pulls.list({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
head: `${context.repo.owner}:${context.ref.replace('refs/heads/', '')}`,
|
|
state: 'open',
|
|
});
|
|
skip = data.length > 0;
|
|
} catch (e) {
|
|
core.warning(`PR lookup failed, running checks: ${e.message}`);
|
|
}
|
|
}
|
|
core.setOutput('skip', String(skip));
|
|
if (skip) core.notice('Open PR found for this branch; checks run on the pull_request event.');
|
|
|
|
checks:
|
|
name: Checks (${{ inputs.working-directory }})
|
|
needs: pre
|
|
if: needs.pre.outputs.skip != 'true'
|
|
runs-on: ${{ fromJSON(startsWith(inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest', '{') && (inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest') || format('"{0}"', inputs.runner || vars.SHARED_ACTIONS_RUNNER || 'ubuntu-latest')) }}
|
|
timeout-minutes: 30
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
with:
|
|
lfs: ${{ inputs.lfs }}
|
|
|
|
- name: Run workflow prepare script
|
|
shell: bash
|
|
run: |
|
|
if [ -f "./workflow-prepare.sh" ]; then
|
|
chmod +x ./workflow-prepare.sh
|
|
./workflow-prepare.sh
|
|
fi
|
|
|
|
- name: Detect the package manager
|
|
id: detect
|
|
working-directory: ${{ inputs.working-directory }}
|
|
run: |
|
|
if [ ! -f package.json ]; then
|
|
echo "::error::No package.json in ${{ inputs.working-directory }}."
|
|
exit 1
|
|
fi
|
|
pm=npm
|
|
if [ -f pnpm-lock.yaml ]; then pm=pnpm
|
|
elif [ -f yarn.lock ]; then pm=yarn
|
|
fi
|
|
echo "pm=$pm" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: ${{ inputs.node-version }}
|
|
|
|
- name: Install dependencies
|
|
working-directory: ${{ inputs.working-directory }}
|
|
env:
|
|
PM: ${{ steps.detect.outputs.pm }}
|
|
PNPM_VERSION: ${{ inputs.pnpm-version }}
|
|
run: |
|
|
# Install without updating the lockfile, so a lockfile that does not match package.json fails.
|
|
case "$PM" in
|
|
pnpm | yarn)
|
|
command -v corepack >/dev/null || npm install --global corepack
|
|
corepack enable "$PM"
|
|
;;
|
|
esac
|
|
if [ "$PM" = pnpm ] && [ -n "$PNPM_VERSION" ]; then
|
|
corepack prepare "pnpm@$PNPM_VERSION" --activate
|
|
fi
|
|
case "$PM" in
|
|
pnpm) pnpm install --frozen-lockfile ;;
|
|
yarn) yarn install --immutable ;;
|
|
npm)
|
|
if [ -f package-lock.json ]; then npm ci; else npm install; fi
|
|
;;
|
|
esac
|
|
|
|
- name: Run scripts
|
|
working-directory: ${{ inputs.working-directory }}
|
|
env:
|
|
PM: ${{ steps.detect.outputs.pm }}
|
|
SCRIPTS: ${{ inputs.scripts }}
|
|
REQUIRE_TESTS: ${{ inputs.require-tests }}
|
|
run: |
|
|
if [ "$REQUIRE_TESTS" = true ] && ! jq -e '.scripts.test' package.json >/dev/null; then
|
|
echo "::error::package.json has no test script."
|
|
exit 1
|
|
fi
|
|
ran=()
|
|
IFS=',' read -r -a scripts <<<"$SCRIPTS"
|
|
for script in "${scripts[@]}"; do
|
|
script=$(echo "$script" | xargs)
|
|
[ -n "$script" ] || continue
|
|
if jq -e --arg s "$script" '.scripts[$s]' package.json >/dev/null; then
|
|
echo "::group::$PM run $script"
|
|
"$PM" run "$script"
|
|
echo "::endgroup::"
|
|
ran+=("$script")
|
|
else
|
|
echo "::notice::No '$script' script, skipping."
|
|
fi
|
|
done
|
|
if [ "${#ran[@]}" -eq 0 ]; then
|
|
echo "::warning::None of the scripts ($SCRIPTS) exist in package.json, so nothing was checked."
|
|
fi
|
|
echo "Ran: ${ran[*]:-none} (${PM})" >> "$GITHUB_STEP_SUMMARY"
|