feat: migrate to AWS SDK v3 with complete feature parity (v4.1.2) #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Continuous Integration | |
| on: | |
| push: | |
| branches: [ main, master, feature/*, release/*, hotfix/* ] | |
| pull_request: | |
| branches: [ main, master ] | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Smart change detection and validation | |
| detect-changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| has-code-changes: ${{ steps.changes.outputs.code }} | |
| has-dependency-changes: ${{ steps.changes.outputs.dependencies }} | |
| has-workflow-changes: ${{ steps.changes.outputs.workflows }} | |
| should-run-tests: ${{ steps.decision.outputs.run-tests }} | |
| should-publish: ${{ steps.decision.outputs.publish }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect file changes | |
| uses: dorny/paths-filter@v3 | |
| id: changes | |
| with: | |
| filters: | | |
| code: | |
| - 'index.js' | |
| - 'getAwsOptions.js' | |
| - 'resolveStackOutput.js' | |
| - 'test/**' | |
| dependencies: | |
| - 'package.json' | |
| - 'package-lock.json' | |
| workflows: | |
| - '.github/workflows/**' | |
| - name: Make decisions | |
| id: decision | |
| run: | | |
| # Always run tests for PR or if code/deps changed | |
| if [[ "${{ github.event_name }}" == "pull_request" ]] || \ | |
| [[ "${{ steps.changes.outputs.code }}" == "true" ]] || \ | |
| [[ "${{ steps.changes.outputs.dependencies }}" == "true" ]]; then | |
| echo "run-tests=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "run-tests=false" >> $GITHUB_OUTPUT | |
| fi | |
| # Only publish on main/master push with code changes | |
| if [[ "${{ github.event_name }}" == "push" ]] && \ | |
| [[ "${{ github.ref }}" == "refs/heads/main" || "${{ github.ref }}" == "refs/heads/master" ]] && \ | |
| [[ "${{ steps.changes.outputs.code }}" == "true" ]]; then | |
| echo "publish=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "publish=false" >> $GITHUB_OUTPUT | |
| fi | |
| # Comprehensive testing matrix | |
| test: | |
| name: Test (Node.js ${{ matrix.node-version }}) | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.should-run-tests == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node-version: [18.x, 20.x] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup 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: Run linting | |
| run: | | |
| if npm run lint --if-present; then | |
| echo "Linting passed" | |
| else | |
| echo "No linting script found, skipping" | |
| fi | |
| - name: Run type checking | |
| run: | | |
| if npm run type-check --if-present; then | |
| echo "Type checking passed" | |
| else | |
| echo "No type checking script found, skipping" | |
| fi | |
| - name: Run tests with coverage | |
| run: npm run test:coverage | |
| - name: Upload coverage to Codecov | |
| if: matrix.node-version == '18.x' | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| fail_ci_if_error: false | |
| - name: Run basic integration test | |
| run: npm run test:basic | |
| # Security and quality checks | |
| security: | |
| name: Security & Quality | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.should-run-tests == 'true' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18.x' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Security audit | |
| run: | | |
| echo "Running security audit..." | |
| npm audit --audit-level high | |
| - name: Check for outdated dependencies | |
| run: | | |
| echo "Checking for outdated dependencies..." | |
| npm outdated || echo "Some dependencies may be outdated" | |
| - name: License check | |
| run: | | |
| echo "Validating license compliance..." | |
| if command -v license-checker &> /dev/null; then | |
| npx license-checker --summary | |
| else | |
| echo "License checker not available, skipping" | |
| fi | |
| # Build validation | |
| build: | |
| name: Build Validation | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.should-run-tests == 'true' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18.x' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Validate package.json | |
| run: | | |
| echo "Validating package.json structure..." | |
| node -e " | |
| const pkg = require('./package.json'); | |
| const required = ['name', 'version', 'description', 'main', 'author', 'license']; | |
| const missing = required.filter(field => !pkg[field]); | |
| if (missing.length > 0) { | |
| console.error('Missing required fields:', missing.join(', ')); | |
| process.exit(1); | |
| } | |
| console.log('Package.json validation passed'); | |
| " | |
| - name: Test package installation | |
| run: | | |
| echo "Testing package installation..." | |
| npm pack | |
| PKG_FILE=$(ls *.tgz) | |
| npm install -g "$PKG_FILE" | |
| echo "Package installs successfully" | |
| # Pre-publish validation | |
| pre-publish: | |
| name: Pre-publish Validation | |
| runs-on: ubuntu-latest | |
| needs: [test, security, build] | |
| if: needs.detect-changes.outputs.should-publish == 'true' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18.x' | |
| registry-url: 'https://registry.npmjs.org' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Final test run | |
| run: npm test | |
| - name: Check if version exists on NPM | |
| run: | | |
| CURRENT_VERSION=$(node -p "require('./package.json').version") | |
| echo "Current version: $CURRENT_VERSION" | |
| if npm view @flaconi/serverless-s3-sync@$CURRENT_VERSION version &>/dev/null; then | |
| echo "Version $CURRENT_VERSION already exists on NPM" | |
| echo "Please bump the version before publishing" | |
| exit 1 | |
| else | |
| echo "Version $CURRENT_VERSION is available for publishing" | |
| fi | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Dry run publish | |
| run: npm publish --dry-run --access public | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Publish to NPM | |
| run: | | |
| echo "Publishing to NPM..." | |
| npm publish --access public | |
| echo "Successfully published to NPM" | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| # Status reporting | |
| ci-success: | |
| name: CI Success | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, test, security, build] | |
| if: always() && (needs.detect-changes.outputs.should-run-tests == 'false' || (needs.test.result == 'success' && needs.security.result == 'success' && needs.build.result == 'success')) | |
| steps: | |
| - name: Report success | |
| run: | | |
| echo "All CI checks passed successfully!" | |
| echo "Changes detected: ${{ needs.detect-changes.outputs.has-code-changes }}" | |
| echo "Tests required: ${{ needs.detect-changes.outputs.should-run-tests }}" | |
| echo "Publish ready: ${{ needs.detect-changes.outputs.should-publish }}" |