diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a1362b6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,90 @@ +name: CI + +# Note the coverage gap: a commit pushed to a branch with no pull request open +# yet matches neither trigger, so it runs no CI until the PR exists. +on: + pull_request: + push: + branches: + - main + +concurrency: + group: ci-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + # A container image rather than ruby/setup-ruby: this repo's Actions policy + # is allowed_actions: "selected" and ruby/setup-ruby is not on the + # allow-list. Pulling a plain image needs no allow-listing. Pinned to the + # patch version in .ruby-version. + container: + image: ruby:3.4.5 + steps: + - uses: actions/checkout@v4 + + - uses: actions/cache@v4 + with: + path: vendor/bundle + key: bundle-${{ hashFiles('Gemfile.lock') }} + restore-keys: bundle- + + - name: bundle install + run: | + ruby -v + gem install bundler --no-document + bundle config set --local path 'vendor/bundle' + bundle install --jobs "$(nproc)" + + - name: rspec + run: bundle exec rspec --format documentation --format RspecJunitFormatter --out rspec.xml + + - name: Upload test report + if: always() + uses: actions/upload-artifact@v4 + with: + name: rspec-report + path: rspec.xml + retention-days: 7 + if-no-files-found: warn + + lint: + runs-on: ubuntu-latest + container: + image: ruby:3.4.5 + steps: + - uses: actions/checkout@v4 + + - uses: actions/cache@v4 + with: + path: vendor/bundle + key: bundle-${{ hashFiles('Gemfile.lock') }} + restore-keys: bundle- + + - name: bundle install + run: | + ruby -v + gem install bundler --no-document + bundle config set --local path 'vendor/bundle' + bundle install --jobs "$(nproc)" + + # Non-blocking: .rubocop.yml is empty, so the full default cop set runs + # against code that predates RuboCop being turned on. It currently reports + # 166 offenses across 69 files and exits 1. The step shows as failed in the + # Checks UI while the job stays green. + - name: rubocop + continue-on-error: true + run: bundle exec rubocop --format progress --format junit --out rubocop.xml + + - name: Upload lint report + if: always() + uses: actions/upload-artifact@v4 + with: + name: rubocop-report + path: rubocop.xml + retention-days: 7 + if-no-files-found: warn diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..2ae0948 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,74 @@ +name: Pages + +# Requires GitHub Pages to be enabled for the repo with Source: GitHub Actions. +# actions/deploy-pages calls the Pages Deployments API, which needs a site +# already provisioned with build_type=workflow; the action cannot create one, so +# until an admin does this once the deploy job fails. +# +# Triggered on CI completing rather than on push, so docs are only published for +# a commit whose tests passed. +on: + workflow_run: + workflows: ["CI"] + types: [completed] + branches: [main] + +# One deployment at a time, queued rather than cancelled, so an in-flight +# deploy-pages call is never killed mid-upload. +concurrency: + group: pages + cancel-in-progress: false + +permissions: + contents: read + +jobs: + build: + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + # Container image for the same reason as ci.yml: ruby/setup-ruby is not on + # this repo's selected-actions allow-list. + container: + image: ruby:3.4.5 + steps: + # workflow_run checks out the default branch by default, which would build + # stale docs if main moved while CI was running. Pin to the commit CI + # actually tested. + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.workflow_run.head_sha }} + + - uses: actions/cache@v4 + with: + path: vendor/bundle + key: bundle-${{ hashFiles('Gemfile.lock') }} + restore-keys: bundle- + + - name: bundle install + run: | + gem install bundler --no-document + bundle config set --local path 'vendor/bundle' + bundle install --jobs "$(nproc)" + + - name: Generate YARD docs + run: bundle exec yard doc + + - uses: actions/upload-pages-artifact@v3 + with: + path: doc + + deploy: + needs: build + runs-on: ubuntu-latest + # Scoped to this job so that build, which runs bundle install against a + # lockfile-resolved dependency tree, never holds the ability to call the + # Pages Deployments API or mint an OIDC token for this repo. + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 9c7a4af..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,75 +0,0 @@ -# GitLab CI/CD Pipeline for pug-client-ruby -# Runs tests and generates YARD documentation for GitLab Pages - -# Default configuration applied to all jobs -default: - image: ruby:3.4 - # Cache gems between builds for faster pipeline execution - cache: - paths: - - vendor/bundle - # Common setup for all jobs - before_script: - - ruby -v - - gem install bundler --no-document - - bundle config set --local path 'vendor/bundle' - - bundle install --jobs $(nproc) - -# Define pipeline stages -stages: - - test - - deploy - -# Run RSpec tests -test: - stage: test - script: - # Run RSpec with multiple formatters: documentation for console, JUnit for GitLab - - bundle exec rspec --format documentation --format RspecJunitFormatter --out rspec.xml - artifacts: - reports: - junit: rspec.xml - paths: - - rspec.xml - expire_in: 7 days - when: always - # Run tests on all branches and merge requests - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH - -# Optional: Run RuboCop linter -lint: - stage: test - script: - # Run RuboCop with JUnit formatter for GitLab integration - - bundle exec rubocop --format progress --format junit --out rubocop.xml - artifacts: - reports: - junit: rubocop.xml - paths: - - rubocop.xml - expire_in: 7 days - when: always - allow_failure: true - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH - -# Generate YARD documentation and deploy to GitLab Pages -# This job MUST be named "pages" for GitLab Pages to work -pages: - stage: deploy - # Mark this as a Pages deployment job - pages: true - script: - # Generate YARD documentation to doc/ directory - - bundle exec yard doc - # GitLab Pages requires artifacts in a "public/" directory - - mv doc public - artifacts: - paths: - - public - # Only deploy to Pages from the main branch - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH