Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ workflows/
├── php/
│ ├── pre-release/ # Pre-release validation
│ └── release/ # Create PHP package release
├── javascript/
│ ├── ci/ # Lint, typecheck, build, and optional tests for Node.js/npm libs
│ └── release/ # Publish npm package and create GitHub release
├── package/ # [DEPRECATED] Use php/ instead
│ ├── pre-release/
│ └── release/
Expand Down Expand Up @@ -197,6 +200,123 @@ jobs:

---

## JavaScript / Node.js Workflows

### CI (`javascript/ci`)

Runs lint, optional tests, and mandatory typecheck and build for Node.js/npm libraries.

**Usage:**

```yaml
name: CI

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: JavaScript CI
uses: whilesmart/workflows/javascript/ci@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Optional overrides:
# node_version: '20.x'
# working_directory: '.'
# lint_script: 'lint'
# run_tests: 'true'
```

**Requirements:**

1. `package.json` in the working directory.
2. NPM scripts:
- `lint` (or the script name passed via `lint_script`).
- `typecheck` (mandatory; can be a no-op if you are not using TypeScript).
- `build` (mandatory; used to validate that the library can be built).
- `test` or `test:ci` (required when `run_tests` is set to `'true'`, which is the default).

---

### Release (`javascript/release`)

Publishes a new npm release for Node.js libraries based on the `version` in `package.json`.

**Features:**
- Reads the version from `package.json`.
- Optionally includes release notes from `CHANGELOG.md` (if a matching version entry exists).
- Creates and pushes a `vX.Y.Z` tag.
- Publishes to npm and creates a GitHub Release.
- Supports `dry_run` mode and custom npm `dist-tag` (e.g., `latest`, `next`, `beta`).

**Usage (release from main):**

```yaml
name: Release

on:
push:
branches: [main]

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: JavaScript Release
uses: whilesmart/workflows/javascript/release@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
npm_token: ${{ secrets.NPM_TOKEN }}
# Optional overrides:
# node_version: '20.x'
# working_directory: '.'
# release_branch: 'main'
# npm_registry: 'https://registry.npmjs.org/'
# dist_tag: 'latest'
# dry_run: 'false'
```

**Optional: pre-release / next channel**

```yaml
on:
push:
branches: [next]

jobs:
release-next:
runs-on: ubuntu-latest
steps:
- name: JavaScript Release (next)
uses: whilesmart/workflows/javascript/release@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
npm_token: ${{ secrets.NPM_TOKEN }}
release_branch: 'next'
dist_tag: 'next'
```

**Requirements:**

1. `package.json` with a valid `version` field.
2. The following npm scripts in `package.json` (all mandatory):
- `lint` (or override via `lint_script` input)
- `typecheck` (can be a no-op if not using TypeScript)
- `build` (can be a no-op if no build step is needed)
3. `test` or `test:ci` script (optional, controlled by `run_tests` input)
4. `CHANGELOG.md` (optional but recommended; if present, include an entry like `## [X.Y.Z] - YYYY-MM-DD` for the version).
5. `NPM_TOKEN` secret configured with publish permissions for the target npm registry.

---

## Adding New Languages

To add workflows for a new language:
Expand Down
123 changes: 123 additions & 0 deletions javascript/ci/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: 'JavaScript CI'
description: 'Run lint, typecheck, optional tests, and build for Node.js/npm projects'

inputs:
token:
description: 'GitHub token for authentication'
required: true
node_version:
description: 'Node.js version to use'
required: false
default: 'lts/*'
working_directory:
description: 'Directory containing package.json (relative to repository root)'
required: false
default: '.'
lint_script:
description: 'NPM script name to run for linting'
required: false
default: 'lint'
run_tests:
description: 'Whether to run the test script (test or test:ci)'
required: false
default: 'true'

runs:
using: 'composite'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ inputs.token }}

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node_version }}
cache: 'npm'
cache-dependency-path: ${{ inputs.working_directory }}/package-lock.json

- name: Install dependencies
Comment thread
Lantum-Brendan marked this conversation as resolved.
shell: bash
working-directory: ${{ inputs.working_directory }}
run: |
if [ ! -f "package.json" ]; then
echo "❌ package.json not found in $PWD"
exit 1
fi

Comment on lines +46 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check for package.json existence is redundant here. It's already performed in the 'Install dependencies' step (lines 43-52), which will cause the workflow to exit if the file is not found. Removing this redundant check will make the code cleaner and avoid unnecessary duplication.

if [ -f "package-lock.json" ]; then
echo "📦 Using npm ci"
npm ci
else
echo "📦 Using npm install"
npm install
fi

- name: Run lint
shell: bash
working-directory: ${{ inputs.working_directory }}
run: |
if jq -e ".scripts[\"${{ inputs.lint_script }}\"]" package.json >/dev/null; then
echo "🔎 Running npm run ${{ inputs.lint_script }}..."
npm run ${{ inputs.lint_script }}
else
echo "❌ No \"${{ inputs.lint_script }}\" script defined in package.json"
echo " Please add it or override the lint_script input."
Comment thread
Lantum-Brendan marked this conversation as resolved.
exit 1
fi

- name: Run typecheck
shell: bash
working-directory: ${{ inputs.working_directory }}
run: |
if jq -e '.scripts["typecheck"]' package.json >/dev/null; then
echo "🔡 Running npm run typecheck..."
npm run typecheck
Comment on lines +76 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the 'typecheck' script, the README.md states the 'build' script is 'mandatory' (line 242). If run_build is true and the script is missing, the action should exit with an error to ensure this mandatory step is executed or properly configured as a no-op, maintaining consistency with the documented requirements.

Suggested change
echo "🔡 Running npm run typecheck..."
npm run typecheck
echo "❌ No \"build\" script defined in package.json, but run_build is true. Please define a 'build' script or set 'run_build: false'."
exit 1

else
Comment thread
Lantum-Brendan marked this conversation as resolved.
echo "❌ No \"typecheck\" script defined in package.json"
echo " Please add a typecheck script (it can be a no-op if you are not using TypeScript)."
exit 1
fi

- name: Run tests
if: ${{ inputs.run_tests == 'true' }}
shell: bash
working-directory: ${{ inputs.working_directory }}
run: |
TEST_SCRIPT=""
if jq -e '.scripts["test:ci"]' package.json >/dev/null; then
TEST_SCRIPT="test:ci"
elif jq -e '.scripts["test"]' package.json >/dev/null; then
TEST_SCRIPT="test"
else
echo "❌ No \"test\" or \"test:ci\" script defined in package.json"
echo " Please define one of them to use the JavaScript CI action."
exit 1
fi

echo "🧪 Running npm run $TEST_SCRIPT..."
npm run "$TEST_SCRIPT"

- name: Run build
shell: bash
working-directory: ${{ inputs.working_directory }}
run: |
if jq -e '.scripts["build"]' package.json >/dev/null; then
echo "🏗️ Running npm run build..."
npm run build
else
echo "❌ No \"build\" script defined in package.json"
echo " Please add a build script (it can be a no-op if your project does not need a build step)."
exit 1
fi

- name: Summary
if: success()
shell: bash
run: |
echo "## ✅ JavaScript CI Summary" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "- Node.js version: \`${{ inputs.node_version }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Working directory: \`${{ inputs.working_directory }}\`" >> "$GITHUB_STEP_SUMMARY"
Loading