Build of 3237/merge by @laritakr #3707
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: "build-test-lint" | |
| run-name: Build of ${{ github.ref_name }} by @${{ github.actor }} | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| debug_step: | |
| required: false | |
| description: "Pause the selected step to debug using tmate" | |
| type: choice | |
| default: "" | |
| options: | |
| - "" | |
| - build | |
| - test | |
| - lint | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: samvera/hyku | |
| DOCKER_BUILDKIT: 1 | |
| COMPOSE_DOCKER_CLI_BUILD: 1 | |
| jobs: | |
| build: | |
| strategy: | |
| matrix: | |
| component: ["solr", "web", "worker"] | |
| os: ["ubuntu-latest", "ubuntu-24.04-arm"] | |
| runs-on: ${{ matrix.os }} | |
| defaults: | |
| run: | |
| shell: bash | |
| permissions: write-all | |
| steps: | |
| - name: Determine git sha to checkout | |
| uses: haya14busa/action-cond@v1 | |
| id: gitsha | |
| with: | |
| cond: ${{ github.event_name == 'pull_request' }} | |
| if_true: ${{ github.event.pull_request.head.sha }} | |
| if_false: ${{ github.sha }} | |
| - name: Set env | |
| run: echo "TAG=${GIT_SHA::8}" >> $GITHUB_ENV | |
| env: | |
| GIT_SHA: ${{ steps.gitsha.outputs.value }} | |
| - name: Downcase repo | |
| run: echo "REPO_LOWER=${REPO,,}" >> $GITHUB_ENV | |
| env: | |
| REPO: "${{ github.repository }}" | |
| - name: Set platform from matrix | |
| run: | | |
| if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then | |
| echo "PLATFORM_TAG=amd64" >> $GITHUB_ENV | |
| else | |
| echo "PLATFORM_TAG=arm64" >> $GITHUB_ENV | |
| fi | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Github Container Login | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push ${{ matrix.component }} on ${{ matrix.os }} | |
| uses: docker/build-push-action@v3 | |
| with: | |
| context: . | |
| platforms: linux/${{ env.PLATFORM_TAG }} | |
| target: hyku-${{ matrix.component }} | |
| cache-from: | | |
| type=registry,ref=ghcr.io/samvera/hyku/${{ matrix.component }}:latest | |
| cache-to: type=inline | |
| push: true | |
| tags: | | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.component }}:${{ env.TAG }}-${{ env.PLATFORM_TAG }} | |
| push: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| permissions: write-all | |
| steps: | |
| - name: Determine git sha to checkout | |
| uses: haya14busa/action-cond@v1 | |
| id: gitsha | |
| with: | |
| cond: ${{ github.event_name == 'pull_request' }} | |
| if_true: ${{ github.event.pull_request.head.sha }} | |
| if_false: ${{ github.sha }} | |
| - name: Set env | |
| run: echo "TAG=${GIT_SHA::8}" >> $GITHUB_ENV | |
| env: | |
| GIT_SHA: ${{ steps.gitsha.outputs.value }} | |
| - name: Downcase repo | |
| run: echo "REPO_LOWER=${REPO,,}" >> $GITHUB_ENV | |
| env: | |
| REPO: "${{ github.repository }}" | |
| - name: Github Container Login | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create multiarch manifests | |
| run: | | |
| for component in solr web worker; do | |
| docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$component:${{ env.TAG }} \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$component:${{ env.TAG }}-amd64 \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$component:${{ env.TAG }}-arm64 | |
| done | |
| lint: | |
| needs: push | |
| uses: notch8/actions/.github/workflows/lint.yaml@v1.0.6 | |
| with: | |
| webTarget: hyku-web | |
| workerTarget: hyku-worker | |
| rubocop_cmd: "bundle exec rubocop --parallel --format progress" | |
| test: | |
| needs: push | |
| uses: notch8/actions/.github/workflows/test.yaml@v1.0.6 | |
| with: | |
| confdir: "/app/samvera/hyrax-webapp/solr/conf" | |
| rspec_cmd: "gem install semaphore_test_boosters && bundle && rspec_booster --job $CI_NODE_INDEX/$CI_NODE_TOTAL" | |
| single-tenant-test: | |
| needs: push | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| shell: bash | |
| permissions: write-all | |
| steps: | |
| - name: Determine git sha to checkout | |
| uses: haya14busa/action-cond@v1 | |
| id: gitsha | |
| with: | |
| cond: ${{ github.event_name == 'pull_request' }} | |
| if_true: ${{ github.event.pull_request.head.sha }} | |
| if_false: ${{ github.sha }} | |
| - name: Set env | |
| run: echo "TAG=${GIT_SHA::8}" >> $GITHUB_ENV | |
| env: | |
| GIT_SHA: ${{ steps.gitsha.outputs.value }} | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Github Container Login | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Bring up single-tenant stack | |
| run: docker compose -f docker-compose.single.yml up -d web worker > docker-compose-server.log 2>&1 | |
| - name: Ensure gems are installed in web and worker | |
| run: | | |
| for svc in web worker; do | |
| docker compose -f docker-compose.single.yml exec -T "$svc" \ | |
| sh -lc 'bundle check || bundle install' | |
| done | |
| - name: Wait for web to be ready | |
| run: | | |
| for i in {1..60}; do | |
| if docker compose -f docker-compose.single.yml exec -T web bundle exec rails runner "puts 'ok'" 2>/dev/null | grep -q ok; then | |
| echo "web is ready" | |
| exit 0 | |
| fi | |
| echo "waiting for web... ($i)" | |
| sleep 5 | |
| done | |
| echo "web did not become ready in time" | |
| docker compose -f docker-compose.single.yml ps | |
| exit 1 | |
| - name: Run single-tenant specs | |
| env: | |
| HYKU_MULTITENANT: "false" | |
| SOLR_ENABLE_CLOUD_MODE: "no" | |
| SOLR_COLLECTION: hydra-development | |
| SOLR_COLLECTION_NAME: hydra-development | |
| run: | | |
| docker compose -f docker-compose.single.yml exec -T \ | |
| -e HYKU_MULTITENANT=false \ | |
| -e SOLR_ENABLE_CLOUD_MODE=no \ | |
| -e SOLR_COLLECTION=hydra-development \ | |
| -e SOLR_COLLECTION_NAME=hydra-development \ | |
| web bundle exec rspec \ | |
| spec/models/user_spec.rb \ | |
| spec/models/account_spec.rb \ | |
| spec/models/solr_endpoint_spec.rb \ | |
| spec/jobs/create_solr_collection_job_spec.rb \ | |
| spec/jobs/remove_solr_collection_job_spec.rb \ | |
| spec/lib/hyku_spec.rb \ | |
| --tag ~wip | |
| - name: Verify standalone Solr core and account endpoint | |
| run: | | |
| docker compose -f docker-compose.single.yml exec -T \ | |
| -e HYKU_MULTITENANT=false \ | |
| -e SOLR_COLLECTION=hydra-development \ | |
| -e SOLR_COLLECTION_NAME=hydra-development \ | |
| web bundle exec rails runner " | |
| core = ENV.fetch('SOLR_COLLECTION', 'hydra-development') | |
| account = Account.find_by(cname: ENV.fetch('HYKU_SINGLE_TENANT_CNAME', 'single.tenant.default')) | |
| raise 'No single-tenant account found' unless account | |
| raise 'Account has no SolrEndpoint' if account.solr_endpoint.is_a?(NilSolrEndpoint) | |
| raise \"SolrEndpoint URL does not include core name '#{core}'\" unless account.solr_endpoint.url.include?(core) | |
| base_url = ENV.fetch('SOLR_URL', 'http://solr:8983/solr/') | |
| response = RSolr.connect(url: base_url).get('/solr/admin/cores', params: { action: 'STATUS', core: core }) | |
| raise \"Solr core '#{core}' missing from STATUS response\" unless response.dig('status', core)&.any? | |
| puts \"Standalone Solr core '#{core}' OK — endpoint: #{account.solr_endpoint.url}\" | |
| " | |
| - name: Upload single-tenant logs | |
| uses: notch8/actions/after-care@v1.0.6 | |
| if: always() | |
| env: | |
| COMPOSE_FILE: docker-compose.single.yml | |
| with: | |
| name: single-tenant-${{ env.TAG }} | |
| reports: "single-tenant-*.xml" | |
| - name: Tear down stack | |
| if: always() | |
| run: docker compose -f docker-compose.single.yml down -v --remove-orphans | |
| env-file-lint: | |
| # Guard against a regression class: `${VAR}` shell interpolation of any | |
| # form placed inside `.env`. It is not reliably expanded through env_file: | |
| # the `${VAR:-default}` form is only handled on newer Compose (>= ~2.24), | |
| # and the dotenv CLI that stack_car (`sc`) wraps compose with mangles it | |
| # (e.g. `${FCREPO_HOST:-fcrepo}` becomes `:-fcrepo}`). Even plain `${VAR}` | |
| # depends on how the file is consumed. Defaults belong in the compose | |
| # `environment:` block, which is always interpolated; `.env` stays literal. | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Reject `${...}` interpolation in .env | |
| run: | | |
| # Compose files (docker-compose*.yml) may use ${VAR:-default} freely; the | |
| # compose file is always interpolated. Only `.env` is unreliable, because | |
| # its values reach the container via env_file passthrough and the | |
| # dotenv CLI. Note: `%{...}` (Ruby format, e.g. HYKU_DEFAULT_HOST) is fine. | |
| env_matches=$(grep -nE '\$\{' .env 2>/dev/null || true) | |
| if [ -n "$env_matches" ]; then | |
| echo "::error::Found \${...} interpolation in .env. This is NOT reliably expanded via docker-compose env_file (only on Compose >= ~2.24) and is mangled by the dotenv CLI used by stack_car, so the container may receive a literal/garbled value. Use a plain literal in .env and put any overridable default in the docker-compose.yml 'environment:' (x-app-env) block instead." | |
| echo "$env_matches" | |
| exit 1 | |
| fi | |
| echo "No \${...} interpolation found in .env" | |
| reports: | |
| if: always() | |
| needs: [test, lint, single-tenant-test] | |
| uses: notch8/actions/.github/workflows/report.yaml@v1.0.6 |