Skip to content

Merge pull request #103 from gmoon/v4.0-refactor #333

Merge pull request #103 from gmoon/v4.0-refactor

Merge pull request #103 from gmoon/v4.0-refactor #333

Workflow file for this run

name: Node CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# Security audit - quick check for critical vulnerabilities
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Security audit (runtime deps only)
# The published package only ships @aws-sdk/client-s3 as a
# runtime dep — dev-tree vulns (artillery's transitive uuid,
# vitest's vite, etc.) don't reach consumers. Gate on runtime
# exposure only; track dev-tree vulns separately via Dependabot.
run: npm audit --audit-level critical --omit=dev
# Core tests - build, lint, type-check, unit tests
test:
name: "Core Tests"
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22, 23]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run type-check
- name: Build
run: npm run build
- name: Unit tests
run: npm run test:unit
- name: Coverage
run: npm run test:coverage
if: matrix.node-version == 23
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
if: matrix.node-version == 23
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# Examples smoke test - boots each example on a free port and asserts
# health/200/404 paths. Catches example regressions (route syntax,
# error handler shape) that unit tests can't see.
smoke-tests:
name: "Examples Smoke"
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run smoke tests
run: npm run test:smoke
# Validation tests - comprehensive functionality testing
validation-tests:
name: "Validation Tests"
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run validation tests
run: make test-validation-docker
- name: Upload validation test results
uses: actions/upload-artifact@v4
if: always()
with:
name: validation-test-results
path: |
test-results-*.json
load-test-results-*.json
*.log
if-no-files-found: ignore
# Performance tests - load testing with Artillery
performance-tests:
name: "Performance Tests"
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run load tests
run: make artillery-docker
- name: Upload performance test results
uses: actions/upload-artifact@v4
if: always()
with:
name: performance-test-results
path: |
load-test-results-*.json
*.log
if-no-files-found: ignore
# Create version tag and draft release on merge to master
create-tag-and-draft-release:
name: "Create Tag and Draft Release"
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
needs: [test, smoke-tests, validation-tests, performance-tests]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get package version
id: package-version
run: echo "version=v$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Check if tag exists
id: check-tag
run: |
if git rev-parse "${{ steps.package-version.outputs.version }}" >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create and push tag
if: steps.check-tag.outputs.exists == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.package-version.outputs.version }}" -m "Release ${{ steps.package-version.outputs.version }}"
git push origin "${{ steps.package-version.outputs.version }}"
- name: Get merge commit message
id: commit-message
run: |
# Get the commit message and escape it for JSON
COMMIT_MSG=$(git log -1 --pretty=format:"%B" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
echo "message=$COMMIT_MSG" >> $GITHUB_OUTPUT
- name: Create draft release
if: steps.check-tag.outputs.exists == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ steps.package-version.outputs.version }}" \
--title "Release ${{ steps.package-version.outputs.version }}" \
--notes "${{ steps.commit-message.outputs.message }}" \
--draft \
--target "${{ steps.package-version.outputs.version }}"
# Package verification - ensure package contents are correct
package-verification:
name: "Package Verification"
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Create package (verification only)
run: npm pack
- name: Verify package contents
run: |
echo "📦 Package contents:"
tar -tzf s3proxy-*.tgz | sort
echo ""
echo "📊 Package size:"
ls -lh s3proxy-*.tgz
echo ""
echo "🔍 Verifying required files are present:"
tar -tzf s3proxy-*.tgz | grep -E "(package\.json|README\.md|LICENSE|dist/)" || exit 1
- name: Test package installation
run: |
mkdir test-install
cd test-install
npm init -y
npm install ../s3proxy-*.tgz
node -e "import('s3proxy').then(pkg => { console.log('✅ Package installs correctly:', Object.keys(pkg)); }).catch(err => { console.error('❌ Package import failed:', err); process.exit(1); })"
- name: Cleanup verification artifacts
run: rm -f s3proxy-*.tgz