From 731feea10439cd876f2237d600e9bccfb8344c41 Mon Sep 17 00:00:00 2001 From: Tom de Bruijn Date: Mon, 30 Sep 2024 18:10:31 +0200 Subject: [PATCH] Move CI to GitHub Actions I've kept the matrix generator script to run the package tests and extra tests for each Node.js version. Also added Node.js 24 to the build matrix. --- .github/workflows/ci.yml | 338 +++++++++++++++++++++++++++++++++++++++ .semaphore/semaphore.yml | 249 ---------------------------- README.md | 2 +- Rakefile | 217 ++++++++++++------------- build_matrix.yml | 242 +++++++++++++++------------- script/lint_git | 22 --- script/setup | 34 ---- 7 files changed, 570 insertions(+), 534 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .semaphore/semaphore.yml delete mode 100755 script/lint_git delete mode 100755 script/setup diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..9506192f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,338 @@ +# DO NOT EDIT +# This is a generated file by the `rake build_matrix:github:generate` task. +# See `build_matrix.yml` for the build matrix. +# Generate this file with `rake build_matrix:github:generate`. +--- +name: Node.js package CI +'on': + push: + branches: + - main + - develop + pull_request: + types: + - opened + - reopened + - synchronize + schedule: + - cron: 0 0 * * 1-5 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: "${{ !contains(github.ref, 'main')}}" +env: + RUNNING_IN_CI: 'true' + NODE_ENV: test + _PACKAGE_CACHE: v3 +jobs: + validation: + name: Validation + runs-on: ubuntu-latest + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Validate CI setup + run: rake build_matrix:github:validate + lint-git: + name: Git linter (Lintje) + needs: validation + runs-on: ubuntu-latest + if: "${{ github.event_name != 'schedule' }}" + steps: + - name: Checkout project + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Run Git linter + uses: lintje/action@v0.11 + lint-ruby: + name: Ruby linter (RuboCop) + needs: validation + runs-on: ubuntu-latest + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' + bundler-cache: true + - name: Run RuboCop + run: bundle exec rubocop + lint-js: + name: JavaScript linter (Prettier) + needs: validation + runs-on: ubuntu-latest + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install dependencies + run: mono bootstrap + - name: Node.js Lint (Prettier) + run: npm run lint + integration-tests: + name: Integration tests (${{matrix.name}}) + needs: validation + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: Express + Redis + test-app: express-redis + - name: Express + Knex.js + test-app: express-knex + - name: Koa + MySQL + test-app: koa-mysql + - name: Koa + Mongo + test-app: koa-mongo + - name: Express + Mongoose + test-app: express-mongoose + - name: Express + Postgres + test-app: express-postgres + - name: Express + Apollo + test-app: express-apollo + - name: Express + Yoga + test-app: express-yoga + - name: Express + Prisma + Postgres + test-app: express-prisma-postgres + - name: Express + Prisma + Mongo + test-app: express-prisma-mongo + - name: Next.js + test-app: nextjs + - name: Nest.js + test-app: nestjs + - name: Fastify + test-app: fastify + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Run integration tests + run: script/integration_test_app ${{matrix.test-app}} +build_24: + name: Node.js 24 - Build + needs: validation + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + - name: Install dependencies + run: tmp/mono/bin/mono bootstrap --ci + - name: Build package + run: tmp/mono/bin/mono build + - name: Check install report + run: 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' +test_24_unit: + name: Node.js 24 - Tests + needs: build_24 + env: + NODE_VERSION: '24' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + - name: Run tests + run: mono test + - name: Run tests for install failure + run: npm run test:failure +test_24_extra_diagnose: + name: Node.js 24 - Extra test - diagnose + needs: build_24 + env: + NODE_VERSION: '24' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Run tests + run: | + git submodule init + git submodule update + LANGUAGE=nodejs test/integration/diagnose/bin/test +build_22: + name: Node.js 22 - Build + needs: validation + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Install dependencies + run: tmp/mono/bin/mono bootstrap --ci + - name: Build package + run: tmp/mono/bin/mono build + - name: Check install report + run: 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' +test_22_unit: + name: Node.js 22 - Tests + needs: build_22 + env: + NODE_VERSION: '22' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Run tests + run: mono test + - name: Run tests for install failure + run: npm run test:failure +test_22_extra_diagnose: + name: Node.js 22 - Extra test - diagnose + needs: build_22 + env: + NODE_VERSION: '22' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Run tests + run: | + git submodule init + git submodule update + LANGUAGE=nodejs test/integration/diagnose/bin/test +build_20: + name: Node.js 20 - Build + needs: validation + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install dependencies + run: tmp/mono/bin/mono bootstrap --ci + - name: Build package + run: tmp/mono/bin/mono build + - name: Check install report + run: 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' +test_20_unit: + name: Node.js 20 - Tests + needs: build_20 + env: + NODE_VERSION: '20' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Run tests + run: mono test + - name: Run tests for install failure + run: npm run test:failure +test_20_extra_diagnose: + name: Node.js 20 - Extra test - diagnose + needs: build_20 + env: + NODE_VERSION: '20' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Run tests + run: | + git submodule init + git submodule update + LANGUAGE=nodejs test/integration/diagnose/bin/test +build_18: + name: Node.js 18 - Build + needs: validation + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + - name: Install dependencies + run: tmp/mono/bin/mono bootstrap --ci + - name: Build package + run: tmp/mono/bin/mono build + - name: Check install report + run: 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' +test_18_unit: + name: Node.js 18 - Tests + needs: build_18 + env: + NODE_VERSION: '18' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Checkout Mono + uses: actions/checkout@v4 + with: + repository: appsignal/mono + path: tmp/mono + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + - name: Run tests + run: mono test + - name: Run tests for install failure + run: npm run test:failure +test_18_extra_diagnose: + name: Node.js 18 - Extra test - diagnose + needs: build_18 + env: + NODE_VERSION: '18' + steps: + - name: Checkout project + uses: actions/checkout@v4 + - name: Run tests + run: | + git submodule init + git submodule update + LANGUAGE=nodejs test/integration/diagnose/bin/test diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml deleted file mode 100644 index 01d4728c..00000000 --- a/.semaphore/semaphore.yml +++ /dev/null @@ -1,249 +0,0 @@ -# DO NOT EDIT -# This is a generated file by the `rake build_matrix:semaphore:generate` task. -# See `build_matrix.yml` for the build matrix. -# Generate this file with `rake build_matrix:semaphore:generate`. ---- -version: v1.0 -name: AppSignal for Node.js -agent: - machine: - type: e1-standard-2 - os_image: ubuntu2004 -auto_cancel: - running: - when: branch != 'main' AND branch != 'develop' -global_job_config: - env_vars: - - name: RUNNING_IN_CI - value: 'true' - - name: NODE_ENV - value: test - - name: _PACKAGE_CACHE - value: v3 - - name: _BUNDLER_CACHE - value: v2 - prologue: - commands: - - checkout - - '[ -n "$NODE_VERSION" ] && sem-version node $NODE_VERSION || echo Skipping Node.js - install' - - npm i -g npm@9.9.2 - - script/setup - - source ~/.bashrc -blocks: -- name: Validation - dependencies: [] - task: - jobs: - - name: Validate CI setup - commands: - - rake build_matrix:semaphore:validate -- name: Linters - dependencies: [] - task: - jobs: - - name: Ruby Lint (RuboCop) - commands: - - cache restore $_BUNDLER_CACHE-bundler-$(checksum Gemfile.lock) - - bundle config set clean 'true' - - bundle config set path .bundle - - bundle install --jobs=3 --retry=3 - - cache store $_BUNDLER_CACHE-bundler-$(checksum Gemfile.lock) .bundle - - bundle exec rubocop - - name: Node.js Lint (Prettier) - env_vars: - - name: NODE_VERSION - value: '18' - commands: - - cache restore - - mono bootstrap --ci - - cache store - - npm run lint - - name: Git Lint (Lintje) - commands: - - script/lint_git -- name: Integration tests - dependencies: - - Validation - task: - jobs: - - name: Express + Redis - commands: - - script/integration_test_app express-redis - - name: Express + Knex.js - commands: - - script/integration_test_app express-knex - - name: Koa + MySQL - commands: - - script/integration_test_app koa-mysql - - name: Koa + Mongo - commands: - - script/integration_test_app koa-mongo - - name: Express + Mongoose - commands: - - script/integration_test_app express-mongoose - - name: Express + Postgres - commands: - - script/integration_test_app express-postgres - - name: Express + Apollo - commands: - - script/integration_test_app express-apollo - - name: Express + Yoga - commands: - - script/integration_test_app express-yoga - - name: Express + Prisma + Postgres - commands: - - script/integration_test_app express-prisma-postgres - - name: Express + Prisma + Mongo - commands: - - script/integration_test_app express-prisma-mongo - - name: Next.js - commands: - - script/integration_test_app nextjs - - name: Nest.js - commands: - - script/integration_test_app nestjs - - name: Fastify - commands: - - script/integration_test_app fastify -- name: Node.js 22 - Build - dependencies: - - Validation - task: - env_vars: - - name: NODE_VERSION - value: '22' - prologue: - commands: - - cache restore - - mono bootstrap --ci - - cache store - jobs: - - name: Build - commands: - - mono build - - cache delete $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID dist - - cache delete $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID ext - - cache delete $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID build - - 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' -- name: Node.js 22 - Tests - dependencies: - - Node.js 22 - Build - task: - env_vars: - - name: NODE_VERSION - value: '22' - - name: _APPSIGNAL_EXTENSION_INSTALL - value: 'false' - prologue: - commands: - - cache restore - - cache restore $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - mono bootstrap --ci - jobs: - - name: Test package - commands: - - mono test - - npm run test:failure - - name: Extra test - diagnose - commands: &1 - - git submodule init - - git submodule update - - LANGUAGE=nodejs test/integration/diagnose/bin/test -- name: Node.js 20 - Build - dependencies: - - Validation - task: - env_vars: - - name: NODE_VERSION - value: '20' - prologue: - commands: - - cache restore - - mono bootstrap --ci - - cache store - jobs: - - name: Build - commands: - - mono build - - cache delete $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID dist - - cache delete $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID ext - - cache delete $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID build - - 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' -- name: Node.js 20 - Tests - dependencies: - - Node.js 20 - Build - task: - env_vars: - - name: NODE_VERSION - value: '20' - - name: _APPSIGNAL_EXTENSION_INSTALL - value: 'false' - prologue: - commands: - - cache restore - - cache restore $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - mono bootstrap --ci - jobs: - - name: Test package - commands: - - mono test - - npm run test:failure - - name: Extra test - diagnose - commands: *1 -- name: Node.js 18 - Build - dependencies: - - Validation - task: - env_vars: - - name: NODE_VERSION - value: '18' - prologue: - commands: - - cache restore - - mono bootstrap --ci - - cache store - jobs: - - name: Build - commands: - - mono build - - cache delete $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID dist - - cache delete $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID ext - - cache delete $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache store $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID build - - 'cat ext/install.report; cat ext/install.report | grep ''"status": "success"''' -- name: Node.js 18 - Tests - dependencies: - - Node.js 18 - Build - task: - env_vars: - - name: NODE_VERSION - value: '18' - - name: _APPSIGNAL_EXTENSION_INSTALL - value: 'false' - prologue: - commands: - - cache restore - - cache restore $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - cache restore $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID - - mono bootstrap --ci - jobs: - - name: Test package - commands: - - mono test - - npm run test:failure - - name: Extra test - diagnose - commands: *1 diff --git a/README.md b/README.md index d5346c4c..fc2f3a29 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The AppSignal for Node.js library. - [Documentation][docs] - [Support][contact] -![npm (scoped)](https://img.shields.io/npm/v/@appsignal/nodejs) [![Build Status](https://appsignal.semaphoreci.com/badges/appsignal-nodejs/branches/main.svg?style=shields&key=7dd9fe64-f1d5-437b-a5b7-8ac337a26c5b)](https://appsignal.semaphoreci.com/projects/appsignal-nodejs) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) +![npm (scoped)](https://img.shields.io/npm/v/@appsignal/nodejs) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) ## Installation diff --git a/Rakefile b/Rakefile index e37d6c92..77bf050b 100644 --- a/Rakefile +++ b/Rakefile @@ -3,149 +3,128 @@ require "set" require "yaml" +CI_WORKFLOW_FILE = ".github/workflows/ci.yml" + namespace :build_matrix do - namespace :semaphore do + namespace :github do task :generate do yaml = YAML.load_file("build_matrix.yml") matrix = yaml["matrix"] - semaphore = yaml["semaphore"] - builds = [] + github = yaml["github"] + jobs = {} matrix["nodejs"].each do |nodejs| nodejs_version = nodejs["nodejs"] - setup = nodejs.fetch("setup", []) - env_vars = nodejs.fetch("env_vars", []) - build_block_name = "Node.js #{nodejs_version} - Build" - build_block = build_semaphore_task( - "name" => build_block_name, - "dependencies" => ["Validation"], - "task" => { - "env_vars" => env_vars + [ - { - "name" => "NODE_VERSION", - "value" => nodejs_version - } - ], - "prologue" => { - "commands" => setup + [ - "cache restore", - "mono bootstrap --ci", - "cache store" - ] + job_name = "Node.js #{nodejs_version}" + build_job_key = "build_#{nodejs_version}" + jobs[build_job_key] = { + "name" => "#{job_name} - Build", + "needs" => "validation", + "steps" => [ + { + "name" => "Checkout project", + "uses" => "actions/checkout@v4" }, - "jobs" => [ - build_semaphore_job( - "name" => "Build", - "commands" => [ - "mono build", - "cache delete $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "cache store $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID dist", - "cache delete $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "cache store $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID ext", - "cache delete $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "cache store $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID build", - "cat ext/install.report; cat ext/install.report | grep '\"status\": \"success\"'" - ] - ) - ] - } - ) - builds << build_block + { + "name" => "Checkout Mono", + "uses" => "actions/checkout@v4", + "with" => { "repository" => "appsignal/mono" }, + "path" => "tmp/mono" + }, + { + "name" => "Install Node.js", + "uses" => "actions/setup-node@v4", + "with" => { "node-version" => nodejs_version } + }, + { + "name" => "Install dependencies", + "run" => "tmp/mono/bin/mono bootstrap --ci" + }, + { + "name" => "Build package", + "run" => "tmp/mono/bin/mono build" + }, + { + "name" => "Check install report", + "run" => + "cat ext/install.report; cat ext/install.report | grep '\"status\": \"success\"'" + } + ] + } - primary_block_name = "Node.js #{nodejs_version} - Tests" - primary_jobs = [] - package = matrix["package"] - primary_jobs << build_semaphore_job( - "name" => "Test package", - "commands" => ([ - "mono test" - ] + package.fetch("extra_commands", [])).compact - ) + jobs["test_#{nodejs_version}_unit"] = { + "name" => "#{job_name} - Tests", + "needs" => build_job_key, + "env" => { "NODE_VERSION" => nodejs_version }, + "steps" => [ + { + "name" => "Checkout project", + "uses" => "actions/checkout@v4" + }, + { + "name" => "Checkout Mono", + "uses" => "actions/checkout@v4", + "with" => { "repository" => "appsignal/mono" }, + "path" => "tmp/mono" + }, + { + "name" => "Install Node.js", + "uses" => "actions/setup-node@v4", + "with" => { "node-version" => nodejs_version } + }, + { + "name" => "Run tests", + "run" => "mono test" + }, + { + "name" => "Run tests for install failure", + "run" => "npm run test:failure" + } + ] + } # Run extra tests against specific package versions. If configured, # run the extra tests configured for the package. - package.fetch("extra_tests", []).each do |test_name, extra_tests| - primary_jobs << build_semaphore_job( - "name" => "Extra test - #{test_name}", - "commands" => extra_tests - ) - end - primary_block = - build_semaphore_task( - "name" => primary_block_name, - "dependencies" => [build_block_name], - "task" => { - "env_vars" => env_vars + [ - { - "name" => "NODE_VERSION", - "value" => nodejs_version - }, - { - "name" => "_APPSIGNAL_EXTENSION_INSTALL", - "value" => "false" - } - ], - "prologue" => { - "commands" => setup + [ - "cache restore", - "cache restore $_PACKAGE_CACHE-dist-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "cache restore $_PACKAGE_CACHE-ext-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "cache restore $_PACKAGE_CACHE-build-v$NODE_VERSION-$SEMAPHORE_WORKFLOW_ID", - "mono bootstrap --ci" - ] + matrix["package"] + .fetch("extra_tests", {}) + .each do |test_key, command| + jobs["test_#{nodejs_version}_extra_#{test_key}"] = { + "name" => "#{job_name} - Extra test - #{test_key}", + "needs" => build_job_key, + "env" => { "NODE_VERSION" => nodejs_version }, + "steps" => [ + { + "name" => "Checkout project", + "uses" => "actions/checkout@v4" }, - "jobs" => primary_jobs - } - ) - builds << primary_block + { + "name" => "Run tests", + "run" => command.clone + } + ] + } + end end - semaphore["blocks"] += builds + github.merge!(jobs) header = "# DO NOT EDIT\n" \ - "# This is a generated file by the `rake build_matrix:semaphore:generate` task.\n" \ + "# This is a generated file by the `rake build_matrix:github:generate` task.\n" \ "# See `build_matrix.yml` for the build matrix.\n" \ - "# Generate this file with `rake build_matrix:semaphore:generate`.\n" - generated_yaml = header + YAML.dump(semaphore) - File.write(".semaphore/semaphore.yml", generated_yaml) - puts "Generated `.semaphore/semaphore.yml`" - puts "Task count: #{builds.length}" - puts "Job count: #{builds.sum { |block| block["task"]["jobs"].count }}" + "# Generate this file with `rake build_matrix:github:generate`.\n" + generated_yaml = header + YAML.dump(github) + File.write(CI_WORKFLOW_FILE, generated_yaml) + puts "Generated `#{CI_WORKFLOW_FILE}`" + puts "Job count: #{jobs.length}" end task :validate => :generate do - `git status | grep .semaphore/semaphore.yml 2>&1` + `git status | grep #{CI_WORKFLOW_FILE} 2>&1` if $?.exitstatus.zero? # rubocop:disable Style/SpecialGlobalVars - puts "The `.semaphore/semaphore.yml` is modified. The changes were not committed." - puts "Please run `rake build_matrix:semaphore:generate` and commit the changes." + puts "The `#{CI_WORKFLOW_FILE}` is modified. The changes were not committed." + puts "Please run `rake build_matrix:github:generate` and commit the changes." exit 1 end end end end - -def build_semaphore_task(task_hash) - { - "name" => task_hash.delete("name") { raise "`name` key not found for task" }, - "dependencies" => [], - "task" => task_hash.delete("task") { raise "`task` key not found for task" } - }.merge(task_hash) -end - -def build_semaphore_job(job_hash) - { - "name" => job_hash.delete("name") { "`name` key not found" }, - "commands" => [] - }.merge(job_hash) -end - -def package_has_tests?(package) - test_dir = File.join(package, "src/__tests__") - # Has a dedicated test dir and it contains files - return true if Dir.exist?(test_dir) && Dir.glob(File.join(test_dir, "**", "*.*s")).any? - - Dir - .glob(File.join(package, "**/*.test.*s")) - .reject { |file| file.include?("/node_modules/") } - .any? -end diff --git a/build_matrix.yml b/build_matrix.yml index 9edc95b9..7bf7cbd9 100644 --- a/build_matrix.yml +++ b/build_matrix.yml @@ -1,118 +1,142 @@ -semaphore: # Default `.semaphore/semaphore.yml` contents - version: v1.0 - name: AppSignal for Node.js - agent: - machine: - type: e1-standard-2 - os_image: ubuntu2004 - auto_cancel: - running: - when: branch != 'main' AND branch != 'develop' - global_job_config: - env_vars: - - name: RUNNING_IN_CI - value: 'true' - - name: NODE_ENV - value: test - - name: _PACKAGE_CACHE - value: v3 - - name: _BUNDLER_CACHE - value: v2 - prologue: - commands: - - checkout - - "[ -n \"$NODE_VERSION\" ] && sem-version node $NODE_VERSION || echo Skipping Node.js install" - - npm i -g npm@9.9.2 - - # Mono setup - - script/setup - - source ~/.bashrc - blocks: - - name: Validation - dependencies: [] - task: - jobs: +github: # Default `.github/workflows/ci.yml` contents + name: Node.js package CI + "on": + push: + branches: + - main + - develop + pull_request: + types: + - opened + - reopened + - synchronize + schedule: + - cron: 0 0 * * 1-5 + + concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: "${{ !contains(github.ref, 'main')}}" + + env: + RUNNING_IN_CI: "true" + NODE_ENV: test + _PACKAGE_CACHE: v3 + + jobs: + validation: + name: Validation + runs-on: ubuntu-latest + steps: + - name: "Checkout project" + uses: actions/checkout@v4 + - name: Validate CI setup - commands: - - rake build_matrix:semaphore:validate - - name: Linters - dependencies: [] - task: - jobs: - - name: Ruby Lint (RuboCop) - commands: - - cache restore $_BUNDLER_CACHE-bundler-$(checksum Gemfile.lock) - - bundle config set clean 'true' - - bundle config set path .bundle - - bundle install --jobs=3 --retry=3 - - cache store $_BUNDLER_CACHE-bundler-$(checksum Gemfile.lock) .bundle - - bundle exec rubocop - - name: Node.js Lint (Prettier) - env_vars: - - name: NODE_VERSION - value: "18" - commands: - - cache restore - - mono bootstrap --ci - - cache store - - npm run lint - - name: Git Lint (Lintje) - commands: - - script/lint_git - - name: Integration tests - dependencies: ["Validation"] - task: - jobs: - - name: Express + Redis - commands: - - script/integration_test_app express-redis - - name: Express + Knex.js - commands: - - script/integration_test_app express-knex - - name: Koa + MySQL - commands: - - script/integration_test_app koa-mysql - - name: Koa + Mongo - commands: - - script/integration_test_app koa-mongo - - name: Express + Mongoose - commands: - - script/integration_test_app express-mongoose - - name: Express + Postgres - commands: - - script/integration_test_app express-postgres - - name: Express + Apollo - commands: - - script/integration_test_app express-apollo - - name: Express + Yoga - commands: - - script/integration_test_app express-yoga - - name: Express + Prisma + Postgres - commands: - - script/integration_test_app express-prisma-postgres - - name: Express + Prisma + Mongo - commands: - - script/integration_test_app express-prisma-mongo - - name: Next.js - commands: - - script/integration_test_app nextjs - - name: Nest.js - commands: - - script/integration_test_app nestjs - - name: Fastify - commands: - - script/integration_test_app fastify + run: "rake build_matrix:github:validate" + + lint-git: + name: Git linter (Lintje) + needs: validation + runs-on: ubuntu-latest + if: "${{ github.event_name != 'schedule' }}" + steps: + - name: "Checkout project" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Run Git linter + uses: lintje/action@v0.11 + + lint-ruby: + name: Ruby linter (RuboCop) + needs: validation + runs-on: ubuntu-latest + steps: + - name: "Checkout project" + uses: actions/checkout@v4 + + - name: "Install Ruby" + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - name: "Run RuboCop" + run: bundle exec rubocop + + lint-js: + name: JavaScript linter (Prettier) + needs: validation + runs-on: ubuntu-latest + steps: + - name: "Checkout project" + uses: actions/checkout@v4 + + - name: "Checkout Mono" + uses: actions/checkout@v4 + with: + repository: appsignal/mono + + - name: "Install Node.js" + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: "Install dependencies" + run: mono bootstrap + + - name: "Node.js Lint (Prettier)" + run: npm run lint + + integration-tests: + name: Integration tests (${{matrix.name}}) + needs: validation + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: Express + Redis + test-app: express-redis + - name: Express + Knex.js + test-app: express-knex + - name: Koa + MySQL + test-app: koa-mysql + - name: Koa + Mongo + test-app: koa-mongo + - name: Express + Mongoose + test-app: express-mongoose + - name: Express + Postgres + test-app: express-postgres + - name: Express + Apollo + test-app: express-apollo + - name: Express + Yoga + test-app: express-yoga + - name: Express + Prisma + Postgres + test-app: express-prisma-postgres + - name: Express + Prisma + Mongo + test-app: express-prisma-mongo + - name: Next.js + test-app: nextjs + - name: Nest.js + test-app: nestjs + - name: Fastify + test-app: fastify + steps: + - name: "Checkout project" + uses: actions/checkout@v4 + + - name: "Run integration tests" + run: script/integration_test_app ${{matrix.test-app}} matrix: nodejs: + - nodejs: "24" - nodejs: "22" - nodejs: "20" - nodejs: "18" package: - extra_commands: # Run in the package's job - - npm run test:failure extra_tests: # Run as separate jobs for package - diagnose: - - git submodule init - - git submodule update - - LANGUAGE=nodejs test/integration/diagnose/bin/test + diagnose: | + git submodule init + git submodule update + LANGUAGE=nodejs test/integration/diagnose/bin/test diff --git a/script/lint_git b/script/lint_git deleted file mode 100755 index 325a5156..00000000 --- a/script/lint_git +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -eu - -LINTJE_VERSION="0.6.1" - -mkdir -p $HOME/bin -cache_key=v1-lintje-$LINTJE_VERSION -cache restore $cache_key - -# File exists and is executable -if [ -x "$HOME/bin/lintje" ]; then - echo "Restored Lintje $LINTJE_VERSION from cache" -else - echo "Downloading Lintje $LINTJE_VERSION" - curl -L \ - https://github.com/tombruijn/lintje/releases/download/v$LINTJE_VERSION/x86_64-unknown-linux-gnu.tar.gz | \ - tar -xz --directory $HOME/bin - cache store $cache_key $HOME/bin/lintje -fi - -$HOME/bin/lintje $SEMAPHORE_GIT_COMMIT_RANGE diff --git a/script/setup b/script/setup deleted file mode 100755 index f8545c2d..00000000 --- a/script/setup +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -set -eu - -# Change version number to a release/tag available on the mono repo to update it -# https://github.com/appsignal/mono/releases -MONO_VERSION="v0.6.0" - -MONO_PATH="$HOME/mono" - -has_cache=false -if which cache >/dev/null; then - has_cache=true -fi - -if $has_cache; then - echo "Restoring mono cache" - cache restore mono-$MONO_VERSION -fi - -# Download mono if the cache restored nothing -if [ ! -d $MONO_PATH ]; then - mkdir -p $MONO_PATH - curl --location https://github.com/appsignal/mono/archive/refs/tags/$MONO_VERSION.tar.gz | \ - tar -xz --strip-components=1 --directory $MONO_PATH - if $has_cache; then - echo "Storing mono cache" - cache store mono-$MONO_VERSION $MONO_PATH - fi -fi - -cd $MONO_PATH -# Install mono always as it adds itself to the PATH -script/setup