Repository navigation
Update dependency ruby to v4.0.9 #30315
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 | |
| pull_request: {} | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| typescript: | |
| name: TypeScript check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: graphql-codegen | |
| run: yarn run graphql:codegen | |
| - name: tsc on resulting generated files | |
| run: yarn run ts:check | |
| vitest: | |
| name: Vitest | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: Check generated CloudFront and nginx routing files are up to date | |
| run: yarn run routing:check | |
| - name: build | |
| run: COVERAGE=true yarn run test | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| check_name: "Vitest Report" | |
| report_paths: "test/reports/TEST-*.xml" | |
| detailed_summary: true | |
| skip_success_summary: true | |
| - name: Archive HTML test reports | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: vitest-reports | |
| path: test/html_reports/* | |
| - name: Archive coverage report | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: vitest-coverage | |
| path: coverage/* | |
| # The framework-mode build (react-router.config.ts) while the migration is in progress. Off unless the repository | |
| # variable BUILD_FRAMEWORK is set, and not required by anything else. | |
| build-framework: | |
| name: Framework mode build | |
| if: vars.BUILD_FRAMEWORK != '' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: Check that the generated routes are up to date | |
| run: yarn run routes:check | |
| - name: Build | |
| run: yarn run build:framework | |
| - name: Check the output | |
| run: | | |
| test -f build/framework/client/index.html | |
| ls build/framework/client/assets/*.js > /dev/null | |
| - name: Build the assets image | |
| run: > | |
| docker build -f Dockerfile.assets-framework -t intercode-assets-framework:ci | |
| --build-arg REVISION=${{ github.sha }} . | |
| - name: Push the assets image (on main), for the release upload to the static shell bucket | |
| if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' | |
| run: | | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| docker tag intercode-assets-framework:ci ghcr.io/neinteractiveliterature/intercode-assets-framework:${{ github.sha }} | |
| docker push ghcr.io/neinteractiveliterature/intercode-assets-framework:${{ github.sha }} | |
| - name: Check the assets image with and without ASSETS_HOST | |
| run: | | |
| docker run -d --name with-host -e ASSETS_HOST=assets.example.com:3135 -p 8081:80 intercode-assets-framework:ci | |
| docker run -d --name without-host -p 8082:80 intercode-assets-framework:ci | |
| sleep 5 | |
| curl -sf http://localhost:8081/index.html | grep -q 'href="https://assets.example.com:3135/assets/' | |
| curl -sf http://localhost:8082/index.html | grep -q 'href="/assets/' | |
| for port in 8081 8082; do | |
| if curl -sf http://localhost:$port/index.html | grep -q ASSETHOSTPLACEHOLDER; then | |
| echo "placeholder left in index.html on port $port" | |
| exit 1 | |
| fi | |
| manifest=$(curl -sf http://localhost:$port/index.html | grep -o '/assets/manifest-[a-z0-9]*\.js' | head -1) | |
| curl -sf http://localhost:$port$manifest | grep -q __reactRouterManifest | |
| done | |
| - name: Check the assets image as a front server (RAILS_UPSTREAM) | |
| run: | | |
| cat > stub-rails.conf <<'EOF' | |
| server { | |
| listen 80; | |
| location / { | |
| default_type text/plain; | |
| return 200 "RAILS uri=$request_uri host=$http_host proto=$http_x_forwarded_proto\n"; | |
| } | |
| } | |
| EOF | |
| docker network create front | |
| docker run -d --name stub-rails --network front -v "$PWD/stub-rails.conf:/etc/nginx/conf.d/default.conf:ro" nginx | |
| docker run -d --name front --network front -e RAILS_UPSTREAM=stub-rails:80 -p 8083:80 intercode-assets-framework:ci | |
| sleep 5 | |
| # Browsers get the static shell, for any path that isn't a Rails route | |
| curl -sf http://localhost:8083/events/4130 -A 'Mozilla/5.0' | grep -q 'rel="modulepreload"' | |
| # Crawlers get Rails' Open Graph document for the path, with the original Host | |
| curl -sf "http://localhost:8083/events/a%20b/c?x=1" -A 'facebookexternalhit/1.1' -H 'Host: con.example.org' | grep -q 'uri=/og-shell?path=/events/a%20b/c host=con.example.org' | |
| # The Rails routes are proxied | |
| curl -sf -X POST http://localhost:8083/graphql | grep -q 'uri=/graphql' | |
| curl -sf http://localhost:8083/oauth_session/refresh -X POST | grep -q 'uri=/oauth_session/refresh' | |
| # A missing asset is a 404, not the shell | |
| test "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8083/assets/nope.js)" = 404 | |
| bundle-size: | |
| name: Bundle size check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: Build frontend | |
| run: yarn run build:web | |
| - name: Check bundle size | |
| run: yarn run check:bundle-size | |
| minitest: | |
| permissions: write-all | |
| name: Minitest | |
| runs-on: ubuntu-latest | |
| env: | |
| TEST_DATABASE_URL: postgres://postgres:postgres@localhost/intercode_test | |
| RAILS_ENV: test | |
| # the runner has 4 cores; each worker gets its own copy of the test database | |
| PARALLEL_WORKERS: 4 | |
| services: | |
| postgres: | |
| image: postgres:18 | |
| env: | |
| POSTGRES_PASSWORD: postgres | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: ./.github/actions/install-libvips | |
| - name: Upgrade postgres client utilities | |
| run: | | |
| sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' | |
| wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/pgdg.asc &>/dev/null | |
| sudo apt-get update | |
| sudo apt-get install postgresql-client-18 -y | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| bundler-cache: true | |
| - name: Database setup | |
| run: bundle exec rails db:create db:migrate | |
| - name: Run tests | |
| run: TERM=xterm-color bundle exec rails test | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| check_name: "Minitest Report" | |
| report_paths: "test/reports/TEST-*.xml" | |
| detailed_summary: true | |
| skip_success_summary: true | |
| - name: Archive HTML test reports | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: minitest-reports | |
| path: test/html_reports/* | |
| - name: Archive coverage report | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: minitest-coverage | |
| path: coverage/* | |
| minitest-system: | |
| permissions: write-all | |
| name: Minitest system tests | |
| runs-on: ubuntu-latest | |
| env: | |
| TEST_DATABASE_URL: postgres://postgres:postgres@localhost/intercode_test | |
| RAILS_ENV: test | |
| services: | |
| postgres: | |
| image: postgres:18 | |
| env: | |
| POSTGRES_PASSWORD: postgres | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: ./.github/actions/install-libvips | |
| - name: Upgrade postgres client utilities | |
| run: | | |
| sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' | |
| wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/pgdg.asc &>/dev/null | |
| sudo apt-get update | |
| sudo apt-get install postgresql-client-18 -y | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| bundler-cache: true | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: build | |
| run: yarn run build | |
| - name: Database setup | |
| run: bundle exec rails db:create db:migrate | |
| - name: Run tests | |
| run: TERM=xterm-color bundle exec rails test:system | |
| # The framework-mode build, with Rails serving its static shell, until it replaces the build above. Its routes are | |
| # generated from AppRouter.tsx (see script/genRoutes.mts), so all the system tests should pass against it too. | |
| - name: Build framework mode | |
| if: vars.BUILD_FRAMEWORK != '' | |
| run: yarn run build:framework | |
| - name: Prepare the static shell | |
| if: vars.BUILD_FRAMEWORK != '' | |
| run: script/prepareStaticShell.sh | tee -a "$GITHUB_ENV" | |
| - name: Run system tests against the framework-mode shell | |
| if: vars.BUILD_FRAMEWORK != '' | |
| run: TERM=xterm-color bundle exec rails test:system | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| check_name: "Minitest System Test Report" | |
| report_paths: "test/reports/TEST-*.xml" | |
| detailed_summary: true | |
| skip_success_summary: true | |
| - name: Archive HTML test reports | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: minitest-system-reports | |
| path: test/html_reports/* | |
| - name: Archive Capybara screenshots | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: minitest-system-screenshots | |
| path: tmp/capybara/* | |
| if-no-files-found: ignore | |
| - name: Archive coverage report | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: minitest-system-coverage | |
| path: coverage/* | |
| docker-build: | |
| runs-on: ubuntu-latest | |
| name: Build containers | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: yarn install | |
| run: yarn install | |
| - name: Log in to registry | |
| run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| - name: Build frontend bundle | |
| run: yarn run build | |
| - name: Set up Docker Buildx | |
| id: buildx | |
| uses: docker/setup-buildx-action@master | |
| - name: Read .ruby-version | |
| id: ruby-version | |
| run: echo "ruby-version=$(cat .ruby-version)" >> $GITHUB_OUTPUT | |
| - name: Build (and push to registry, if on main) | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| pull: true | |
| push: ${{ github.event_name == 'push' && github.event.ref == 'refs/heads/main' }} | |
| load: ${{ !(github.event_name == 'push' && github.event.ref == 'refs/heads/main') }} | |
| platforms: linux/amd64 | |
| target: production | |
| tags: | | |
| ghcr.io/neinteractiveliterature/intercode:${{ github.sha }} | |
| build-args: | | |
| RUBY_VERSION=${{ steps.ruby-version.outputs.ruby-version }} | |
| NODE_VERSION=${{ steps.node-version.outputs.node-version }} | |
| REVISION=${{ github.sha }} | |
| - name: Check that app can boot | |
| run: > | |
| docker run -e DATABASE_URL=postgresql://fakehost/not_a_real_database | |
| -e AWS_S3_BUCKET=fakebucket | |
| ghcr.io/neinteractiveliterature/intercode:${{ github.sha }} | |
| bin/rails runner 'puts "Hello, world!"' | |
| - name: Build assets only (and push to registry, if on main) | |
| uses: docker/build-push-action@v7 | |
| if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' | |
| with: | |
| context: . | |
| file: Dockerfile.assets | |
| push: ${{ github.event_name == 'push' && github.event.ref == 'refs/heads/main' }} | |
| platforms: linux/amd64 | |
| tags: | | |
| ghcr.io/neinteractiveliterature/intercode-assets:${{ github.sha }} | |
| # Layer on the last released assets image, so the previous release's files stay available (see | |
| # Dockerfile.assets). latest is only retagged when a release is published. | |
| build-args: | | |
| BASEIMAGE=ghcr.io/neinteractiveliterature/intercode:${{ github.sha }} | |
| PREVIOUS_ASSETS_IMAGE=ghcr.io/neinteractiveliterature/intercode-assets:latest | |
| PREVIOUS_ASSETS_RETENTION_DAYS=30 | |
| doc-site: | |
| name: Build doc site | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up docusaurus cache | |
| uses: actions/cache@v6 | |
| with: | |
| path: doc-site/.yarn/.cache/webpack | |
| key: ${{ runner.os }}-doc-site-docusaurus-${{ github.ref }} | |
| restore-keys: | | |
| ${{ runner.os }}-doc-site-docusaurus-${{ github.ref }} | |
| ${{ runner.os }}-doc-site-docusaurus- | |
| - uses: ./.github/actions/install-libvips | |
| - name: Read .node-version | |
| id: node-version | |
| run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT | |
| - name: install node | |
| uses: actions/setup-node@v6 | |
| with: | |
| cache: yarn | |
| node-version: ${{ steps.node-version.outputs.node-version }} | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| bundler-cache: true | |
| - name: Install dependencies for generating Liquid doc JSON | |
| run: gem install yard toys pry --no-doc | |
| - name: yarn install | |
| run: yarn install | |
| - name: Generate GraphQL schema | |
| run: bin/rails graphql:schema:dump | |
| - name: Generate Liquid doc JSON | |
| run: toys update_liquid_doc_json | |
| - name: Build doc site | |
| run: cd doc-site && yarn run docusaurus graphql-to-doc -f && yarn node liquid-to-doc.js && yarn run build | |
| env: | |
| # docusaurus breaks on Node 17+ if we don't do this | |
| NODE_OPTIONS: --openssl-legacy-provider | |
| - name: Compress built site | |
| if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' | |
| run: tar cfz doc-site.tar.gz ./doc-site/build | |
| - name: Store built site | |
| if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: doc-site | |
| path: doc-site.tar.gz | |
| coverage-report: | |
| runs-on: ubuntu-latest | |
| name: Test coverage report | |
| if: github.actor != 'dependabot[bot]' | |
| needs: | |
| - vitest | |
| - minitest | |
| - minitest-system | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v7 | |
| - name: Download Minitest coverage | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: minitest-coverage | |
| path: minitest-coverage | |
| - name: Download Minitest system test coverage | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: minitest-system-coverage | |
| path: minitest-system-coverage | |
| - name: Download Vitest coverage | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: vitest-coverage | |
| path: vitest-coverage | |
| - name: Merge coverage reports | |
| run: ruby scripts/merge_coverage.rb merged-coverage.xml minitest-coverage/coverage.xml minitest-coverage/worker-*/coverage.xml vitest-coverage/cobertura-coverage.xml minitest-system-coverage/coverage.xml | |
| - name: Generate Coverage Report | |
| uses: clearlyip/code-coverage-report-action@v7 | |
| id: code_coverage_report_action | |
| if: ${{ github.actor != 'dependabot[bot]'}} | |
| with: | |
| filename: "merged-coverage.xml" | |
| fail_on_negative_difference: false | |
| artifact_download_workflow_names: "Continuous integration" | |
| only_list_changed_files: true | |
| - name: Add Coverage PR Comment | |
| if: steps.code_coverage_report_action.outputs.file != '' && github.event_name == 'pull_request' && (success() || failure()) | |
| uses: marocchino/sticky-pull-request-comment@v3.0.5 | |
| with: | |
| recreate: true | |
| path: code-coverage-results.md | |
| opentofu-validate: | |
| name: OpenTofu validate (${{ matrix.module }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| module: | |
| - cloudfront_intercode | |
| - forwardemail_receiving | |
| - ses_email_receiving | |
| - intercode_aws_resources | |
| - sentry | |
| - assets_bucket_intercode | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: opentofu/setup-opentofu@v2 | |
| - name: tofu init | |
| run: tofu init -backend=false | |
| working-directory: terraform/modules/${{ matrix.module }} | |
| - name: tofu validate | |
| run: tofu validate | |
| working-directory: terraform/modules/${{ matrix.module }} | |
| update-release-draft: | |
| runs-on: ubuntu-latest | |
| name: Update release draft | |
| if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' | |
| needs: | |
| - typescript | |
| - vitest | |
| - minitest | |
| - minitest-system | |
| - docker-build | |
| - doc-site | |
| - opentofu-validate | |
| outputs: | |
| name: ${{ steps.release-drafter.outputs.name }} | |
| html_url: ${{ steps.release-drafter.outputs.html_url }} | |
| steps: | |
| - uses: release-drafter/release-drafter@v7 | |
| id: release-drafter | |
| with: | |
| config-name: release-drafter.yml | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Format Slack post | |
| id: slack-post | |
| env: | |
| RELEASE_NAME: ${{ steps.release-drafter.outputs.name }} | |
| RELEASE_URL: ${{ steps.release-drafter.outputs.html_url }} | |
| COMMIT_MESSAGES: ${{ join(github.event.commits.*.message, '\n- ') }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| MAX_LENGTH=2800 | |
| BODY=$(printf 'Draft release %s updated:\n\n- %s\n\nTo release Intercode to production, visit: %s' \ | |
| "$RELEASE_NAME" "$COMMIT_MESSAGES" "$RELEASE_URL") | |
| if [ "${#BODY}" -gt "$MAX_LENGTH" ]; then | |
| BODY="${BODY:0:$MAX_LENGTH}"$'\n\n... (truncated; see the full run: '"$RUN_URL"')' | |
| fi | |
| { | |
| echo "text<<SLACK_MSG_EOF_${{ github.run_id }}_${{ github.run_attempt }}" | |
| echo "$BODY" | |
| echo "SLACK_MSG_EOF_${{ github.run_id }}_${{ github.run_attempt }}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Post about drafted release to Slack | |
| id: slack | |
| uses: slackapi/slack-github-action@v3.0.5 | |
| with: | |
| method: chat.postMessage | |
| token: ${{ secrets.SLACKTOKEN }} | |
| payload: | | |
| channel: ${{ secrets.SlackCISuccessNotificationChannelID }} | |
| text: ${{ toJson(steps.slack-post.outputs.text) }} |