Skip to content
Merged
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
31 changes: 31 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Weekly dependency updates, each opened as a pull request against main that must pass the `build` check
# and is merged like any other change (merge commit). Merging releases nothing: a new npm version still
# needs a GitHub Release (see RELEASING.md).
version: 2
updates:
# The workflows pin every action to a commit SHA with a `# vX.Y.Z` comment; Dependabot updates both.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
groups:
github-actions:
patterns: ["*"]
commit-message:
prefix: ci
labels: [dependencies]

# The package has no runtime dependencies; TypeScript only builds dist/.
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
groups:
npm-minor-and-patch:
update-types: [minor, patch]
commit-message:
prefix: deps
labels: [dependencies]
open-pull-requests-limit: 5
151 changes: 151 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
name: Build
run-name: >-
${{ github.event_name == 'pull_request' && format('Checking that #{0} builds', github.event.pull_request.number)
|| format('Building {0}', github.ref_name) }}

# Trunk-based: main is the only long-lived branch. Every pull request and every push to main builds the
# TypeScript sources and runs the tests on each supported Node.js LTS line, and packs the package, but
# nothing is published here: this is a public npm package, and npm versions are permanent, so a release is
# a deliberate act - publishing a GitHub Release v{semver}, which runs publish.yml. The required status
# check is the last job's name, `build`, which passes only when every Node.js version passed.
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

# A newer push to the same pull request cancels the older build; builds of main never cancel each other.
concurrency:
group: build-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.run_id }}
cancel-in-progress: true

env:
# test/live.test.js converts real files against the staging API with a staging token. Without the token
# (a pull request from a fork gets no secrets) those tests are skipped and the mocked tests still run.
CONVERT_API_HOST: stag-v2.convertapi.com

jobs:
test:
name: test (Node ${{ matrix.node }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
node: [20, 22, 24]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node }}
cache: npm

# --ignore-scripts: no dependency runs install scripts on the runner.
- name: Install
run: npm ci --ignore-scripts

- name: Build
run: npm run build

- name: Unit tests
run: node --test test/convertapi.test.js

# The staging API now and then answers 503 (no healthy upstream), so up to three attempts.
- name: Live tests against staging
env:
CONVERT_API_SECRET: ${{ secrets.CONVERTAPI_STAGING_TOKEN }}
run: |
if [ -z "$CONVERT_API_SECRET" ]; then
echo "::warning::The CONVERTAPI_STAGING_TOKEN secret is not available to this run, so the live tests are skipped"
fi
for attempt in 1 2 3; do
if node --test test/live.test.js; then
exit 0
fi
echo "::warning::Attempt $attempt of the live tests failed"
sleep 10
done
echo "::error::The live tests failed three times"
exit 1

build:
name: build
needs: test
# Runs even when a test job failed, so that the required check reports a failure instead of being
# skipped (a skipped required check counts as passed).
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check every Node.js version passed
env:
RESULT: ${{ needs.test.result }}
run: |
if [ "$RESULT" != success ]; then
echo "::error::The tests did not pass on every Node.js version ($RESULT)"
exit 1
fi

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: npm

- name: Install
run: npm ci --ignore-scripts

# The package has no runtime dependencies today; this keeps it that way unless they are clean.
- name: Audit the runtime dependencies
run: npm audit --omit=dev --audit-level=high

- name: Build
run: npm run build

# A pre-release version that sorts below any real release and names the run, so a package
# downloaded from this run can be tried out but never mistaken for a published one.
- name: Pack
id: pack
env:
RUN: ${{ github.run_number }}
SHORT_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
set -euo pipefail
VERSION="0.0.0-ci.$RUN.g${SHORT_SHA:0:7}"
npm version "$VERSION" --no-git-tag-version --ignore-scripts
mkdir out
npm pack --ignore-scripts --pack-destination out
TGZ="out/convertapi-js-$VERSION.tgz"
test -f "$TGZ"
for f in dist/convertapi.js dist/convertapi.d.ts; do
tar -tzf "$TGZ" | grep -qx "package/$f" || { echo "::error::$TGZ has no $f"; exit 1; }
done
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: convertapi-js-${{ steps.pack.outputs.version }}
path: out/
retention-days: 14
if-no-files-found: error

- name: Summary
env:
VERSION: ${{ steps.pack.outputs.version }}
run: |
{
echo "| | |"
echo "|---|---|"
echo "| Package | \`convertapi-js $VERSION\` (artifact only, not published) |"
echo "| Files | $(tar -tzf "out/convertapi-js-$VERSION.tgz" | wc -l) |"
} >> "$GITHUB_STEP_SUMMARY"
Loading
Loading