feat: show loading spinner while image loads #8226
Workflow file for this run
This file contains 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: CI | |
on: | |
push: | |
branches: | |
- 'master' | |
tags: | |
- 'v[0-9]+.[0-9]+.*' | |
pull_request: | |
branches: | |
- 'master' | |
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft] | |
paths-ignore: | |
- '**.md' | |
- 'packages/contentful/migrations/**' | |
workflow_dispatch: | |
env: | |
CTF_CDA_ACCESS_TOKEN: ${{ secrets.CTF_CDA_ACCESS_TOKEN }} | |
CTF_ENVIRONMENT_ID: ${{ vars.CTF_ENVIRONMENT_ID }} | |
CTF_GRAPHQL_ORIGIN: ${{ vars.CTF_GRAPHQL_ORIGIN }} | |
CTF_SPACE_ID: ${{ secrets.CTF_SPACE_ID }} | |
DOCKER_REPOSITORY: ${{ vars.DOCKER_REPOSITORY }} | |
EUROPEANA_API_KEY: ${{ secrets.EUROPEANA_API_KEY }} | |
OAUTH_CLIENT: ${{ secrets.OAUTH_CLIENT }} | |
jobs: | |
annotate: | |
runs-on: ubuntu-latest | |
if: github.event_name == 'pull_request' && contains(github.head_ref, '/EC-') && github.event.action == 'opened' | |
steps: | |
- | |
name: Extract JIRA ticket number | |
run: echo "JIRA_TICKET_NUMBER=$(echo ${{ github.head_ref }} | sed -r 's|^.*/(EC-[0-9]+).*$|\1|')" >> $GITHUB_ENV | |
- | |
name: Link to JIRA ticket on pull request | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: `JIRA ticket: ${process.env.JIRA_TICKET_NUMBER}` | |
}) | |
metadata: | |
runs-on: ubuntu-latest | |
outputs: | |
git-master-dispatch: ${{ steps.git-master-dispatch.outputs.status }} | |
git-master-push: ${{ steps.git-master-push.outputs.status }} | |
git-pr-draft: ${{ steps.git-pr-draft.outputs.status }} | |
git-pr-ready: ${{ steps.git-pr-ready.outputs.status }} | |
docker-labels: ${{ steps.docker.outputs.labels }} | |
docker-tags: ${{ steps.docker.outputs.tags }} | |
docker-version: ${{ steps.docker.outputs.version }} | |
docker-full-tag: ${{ steps.docker-image.outputs.full-tag }} | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Git metadata, master dispatch | |
id: git-master-dispatch | |
if: github.event_name == 'workflow_dispatch' && github.event.ref == 'refs/heads/master' | |
run: echo "status=true" >> $GITHUB_OUTPUT | |
- | |
name: Git metadata, master push | |
id: git-master-push | |
if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' | |
run: echo "status=true" >> $GITHUB_OUTPUT | |
- | |
name: Git metadata, PR draft | |
id: git-pr-draft | |
if: github.event_name == 'pull_request' && github.event.pull_request.draft == true | |
run: echo "status=true" >> $GITHUB_OUTPUT | |
- | |
name: Git metadata, PR ready for review | |
id: git-pr-ready | |
if: github.event_name == 'pull_request' && github.event.pull_request.draft == false | |
run: echo "status=true" >> $GITHUB_OUTPUT | |
- | |
name: Docker metadata | |
id: docker | |
uses: docker/metadata-action@v4 | |
with: | |
images: ${{ env.DOCKER_REPOSITORY }} | |
tags: | | |
type=ref,event=pr | |
type=ref,event=branch | |
type=ref,event=tag | |
type=semver,pattern={{version}} | |
- | |
name: Output Docker image full tag | |
id: docker-image | |
run: | | |
echo "full-tag=${{ env.DOCKER_REPOSITORY }}:${{ steps.docker.outputs.version }}" >> $GITHUB_OUTPUT | |
# Run code linting on master and all PRs (including drafts) | |
lint-code: | |
needs: [metadata] | |
runs-on: ubuntu-latest | |
if: (needs.metadata.outputs.git-master-push == 'true') || (github.event_name == 'pull_request') || (needs.metadata.outputs.git-master-dispatch == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Setup Node | |
uses: actions/setup-node@v3 | |
with: | |
node-version: 18 | |
cache: 'npm' | |
- | |
name: Install eslint | |
run: | | |
npm install --prefix tmp \ | |
eslint@$(jq -Mr '.packages["node_modules/eslint"].version' package-lock.json) \ | |
eslint-plugin-jest@$(jq -Mr '.packages["node_modules/eslint-plugin-jest"].version' package-lock.json) \ | |
eslint-plugin-vue@$(jq -Mr '.packages["node_modules/eslint-plugin-vue"].version' package-lock.json) | |
mv tmp/node_modules ./ | |
- | |
name: Run eslint | |
run: npm run lint | |
# Run style linting on master and all PRs (including drafts) | |
lint-style: | |
needs: [metadata] | |
runs-on: ubuntu-latest | |
if: (needs.metadata.outputs.git-master-push == 'true') || (github.event_name == 'pull_request') || (needs.metadata.outputs.git-master-dispatch == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Setup Node | |
uses: actions/setup-node@v3 | |
with: | |
node-version: 18 | |
cache: 'npm' | |
- | |
name: Install stylelint | |
run: | | |
npm install --prefix tmp \ | |
stylelint@$(jq -Mr '.packages["node_modules/stylelint"].version' package-lock.json) \ | |
stylelint-config-recommended-vue@$(jq -Mr '.packages["node_modules/stylelint-config-recommended-vue"].version' package-lock.json) \ \ | |
stylelint-config-recommended-scss@$(jq -Mr '.packages["node_modules/stylelint-config-recommended-scss"].version' package-lock.json) | |
mv tmp/node_modules ./ | |
- | |
name: Run stylelint | |
run: npm run stylelint | |
# Verify cachers can load in Node.js on master and all PRs (including drafts) | |
test-cachers: | |
needs: [metadata] | |
runs-on: ubuntu-latest | |
if: (needs.metadata.outputs.git-master-push == 'true') || (github.event_name == 'pull_request') || (needs.metadata.outputs.git-master-dispatch == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Setup Node | |
uses: actions/setup-node@v3 | |
with: | |
node-version: 16 | |
cache: 'npm' | |
- | |
name: NPM install | |
run: npm ci --include-workspace-root -w packages/portal | |
- | |
name: List cachers | |
run: npm run cache list | |
# Run unit tests on master (for coverage reports), and all pull requests | |
test-unit: | |
needs: [metadata] | |
runs-on: ubuntu-latest | |
if: (needs.metadata.outputs.git-master-push == 'true') || (github.event_name == 'pull_request') || (needs.metadata.outputs.git-master-dispatch == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Setup Node | |
uses: actions/setup-node@v3 | |
with: | |
node-version: 18 | |
cache: 'npm' | |
- | |
name: NPM install | |
run: npm ci --include-workspace-root -w packages/portal | |
- | |
name: Run unit tests with coverage reporting | |
run: npm run test:coverage:ci | |
- | |
name: Archive code coverage | |
run: | | |
tar -cf test-coverage.tar coverage | |
- | |
name: Upload code coverage | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-coverage | |
path: test-coverage.tar | |
sonarcloud: | |
runs-on: ubuntu-latest | |
needs: [test-unit] | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
with: | |
# For SonarCloud to blame culprits | |
fetch-depth: 0 | |
- | |
name: Download code coverage | |
uses: actions/download-artifact@v4 | |
with: | |
name: test-coverage | |
path: . | |
- | |
name: Unarchive code coverage | |
run: tar -xf test-coverage.tar && rm test-coverage.tar | |
- | |
name: SonarCloud Scan | |
uses: sonarsource/[email protected] | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
# Build, and push to Docker Hub, the final-stage production-ready Docker image, | |
# for use throughout other jobs, and for deployment. | |
docker-build: | |
needs: [metadata] | |
runs-on: ubuntu-latest | |
if: (github.event_name == 'push') || (needs.metadata.outputs.git-pr-ready == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v2 | |
- | |
if: github.actor != 'dependabot[bot]' | |
name: Login to DockerHub | |
uses: docker/login-action@v2 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- | |
name: Build and push | |
uses: docker/build-push-action@v3 | |
with: | |
context: . | |
file: ./packages/portal/Dockerfile | |
pull: true | |
push: ${{ github.actor != 'dependabot[bot]' }} | |
cache-from: type=gha,scope=${{ github.ref_name }}-app | |
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-app | |
tags: ${{ needs.metadata.outputs.docker-tags }} | |
labels: ${{ needs.metadata.outputs.docker-labels }} | |
- | |
name: Build (from cache) and load app image | |
uses: docker/build-push-action@v3 | |
with: | |
context: . | |
file: ./packages/portal/Dockerfile | |
pull: true | |
load: true | |
tags: ${{ needs.metadata.outputs.docker-full-tag }} | |
cache-from: type=gha,scope=${{ github.ref_name }}-app | |
- | |
name: Check image size | |
env: | |
DOCKER_IMAGE_SIZE_LIMIT: '387M' | |
run: | | |
docker_image_size=$(docker image inspect --format '{{.Size}}' ${{ needs.metadata.outputs.docker-full-tag }}) | |
if [ ${docker_image_size} -gt $(numfmt --from=si ${DOCKER_IMAGE_SIZE_LIMIT}) ]; then | |
echo "::error ::Image size $(numfmt --to=si ${docker_image_size}) exceeds limit ${DOCKER_IMAGE_SIZE_LIMIT}" | |
exit 1 | |
else | |
echo "::notice ::Image size $(numfmt --to=si ${docker_image_size}) within limit ${DOCKER_IMAGE_SIZE_LIMIT}" | |
fi | |
# Run size tests on non-draft pull requests | |
test-size: | |
runs-on: ubuntu-latest | |
needs: [metadata, docker-build] | |
if: (needs.metadata.outputs.git-pr-ready == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v2 | |
- | |
name: Build (from cache) and load app image | |
uses: docker/build-push-action@v3 | |
with: | |
context: . | |
file: ./packages/portal/Dockerfile | |
pull: true | |
load: true | |
tags: ${{ needs.metadata.outputs.docker-tags }} | |
cache-from: type=gha,scope=${{ github.ref_name }}-app | |
- | |
name: Build and load size test image | |
uses: docker/build-push-action@v3 | |
with: | |
context: ./packages/portal/tests/size | |
load: true | |
tags: ${{ env.DOCKER_REPOSITORY }}-test-size | |
cache-from: type=gha,scope=${{ github.ref_name }}-test-size | |
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-test-size | |
- | |
name: Prepare resources for size tests | |
run: | | |
docker run --name portal.js --rm -d ${{ needs.metadata.outputs.docker-full-tag }} | |
docker cp portal.js:/app/packages/portal/.nuxt ./.nuxt | |
docker stop portal.js | |
- | |
name: Run size tests | |
run: | | |
docker run \ | |
--mount type=bind,source="$(pwd)"/.nuxt,target=/app/.nuxt \ | |
--mount type=bind,source="$(pwd)"/packages/portal/tests/size/.size-limit.json,target=/app/.size-limit.json \ | |
${{ env.DOCKER_REPOSITORY }}-test-size | |
# Run e2e tests on non-draft pull requests | |
test-e2e: | |
runs-on: ubuntu-latest | |
needs: [metadata, docker-build] | |
if: (needs.metadata.outputs.git-pr-ready == 'true') | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v2 | |
- | |
name: Build (from cache) and load app image | |
uses: docker/build-push-action@v3 | |
with: | |
context: . | |
file: ./packages/portal/Dockerfile | |
pull: true | |
load: true | |
tags: ${{ needs.metadata.outputs.docker-tags }} | |
cache-from: type=gha,scope=${{ github.ref_name }}-app | |
- | |
name: Prepare env for e2e tests | |
run: echo "APP_IMAGE_VERSION=${{ needs.metadata.outputs.docker-version }}" >> $GITHUB_ENV | |
- | |
name: Create e2e test container .env files | |
run: | | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/app/.env | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/nightwatch/.env | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/nightwatch-visual/.env | |
- | |
name: Pull images for e2e tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml pull -q cache chrome-en | |
- | |
name: Build images for e2e tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml build -q nginx nightwatch-features | |
- | |
name: Run e2e tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml run --rm nightwatch-features | |
# Run visual tests on non-draft pull requests, and pushes to master | |
test-visual: | |
runs-on: ubuntu-latest | |
needs: [metadata, docker-build] | |
if: (needs.metadata.outputs.git-master-push == 'true') || (needs.metadata.outputs.git-pr-ready == 'true') || (needs.metadata.outputs.git-master-dispatch == 'true') | |
env: | |
ENABLE_JIRA_SERVICE_DESK_FEEDBACK_FORM: 0 | |
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v2 | |
- | |
name: Build (from cache) and load app image | |
uses: docker/build-push-action@v3 | |
with: | |
context: . | |
file: ./packages/portal/Dockerfile | |
pull: true | |
load: true | |
tags: ${{ needs.metadata.outputs.docker-tags }} | |
cache-from: type=gha,scope=${{ github.ref_name }}-app | |
- | |
name: Prepare env for visual tests | |
run: | | |
echo "APP_IMAGE_VERSION=${{ needs.metadata.outputs.docker-version }}" >> $GITHUB_ENV | |
echo "PERCY_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV | |
echo "PERCY_BRANCH=$(echo ${GITHUB_HEAD_REF:-${GITHUB_REF}} | sed 's|refs/heads/||')" >> $GITHUB_ENV | |
- | |
name: Prepare env for visual tests (PRs only) | |
if: github.event_name == 'pull_request' | |
run: | |
echo "PERCY_PULL_REQUEST=$(jq .pull_request.number ${GITHUB_EVENT_PATH})" >> $GITHUB_ENV | |
- | |
name: Create visual test container .env files | |
run: | | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/app/.env | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/nightwatch/.env | |
envsubst < .github/workflows/support/ci/.env > tests/e2e/docker/nightwatch-visual/.env | |
- | |
name: Pull images for visual tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml pull -q cache chrome-en | |
- | |
name: Build images for visual tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml build -q nginx nightwatch-features | |
- | |
name: Run visual tests | |
run: docker compose -f ./tests/e2e/docker/docker-compose.yml run --rm nightwatch-visual | |
# Deploy to IBM Cloud Kubernetes cluster: | |
# * Pull requests are deployed as new resources in dev namespace | |
# * Pushes to master update the deployment in the test namespace | |
deploy-ibm-cloud: | |
runs-on: ubuntu-latest | |
needs: [metadata, docker-build] | |
if: (github.actor != 'dependabot[bot]') && ((needs.metadata.outputs.git-master-push == 'true') || (needs.metadata.outputs.git-pr-ready == 'true') || (needs.metadata.outputs.git-master-dispatch == 'true')) | |
env: | |
DOCKER_IMAGE_TAG: ${{ needs.metadata.outputs.docker-full-tag }} | |
IBMCLOUD_API_KEY: ${{ secrets.IBMCLOUD_API_KEY }} | |
IBMCLOUD_API_URL: ${{ vars.IBMCLOUD_API_URL }} | |
IBMCLOUD_CLUSTER_NAME: ${{ vars.IBMCLOUD_CLUSTER_NAME }} | |
IBMCLOUD_REGION: ${{ vars.IBMCLOUD_REGION }} | |
steps: | |
- | |
name: Checkout | |
uses: actions/checkout@v3 | |
- | |
name: Prepare env for dev deployments | |
if: github.event_name == 'pull_request' | |
run: | | |
echo "K8S_NAMESPACE=dev" >> $GITHUB_ENV | |
echo "K8S_RESOURCE_NAME=portal-js-${{ needs.metadata.outputs.docker-version }}" >> $GITHUB_ENV | |
echo "K8S_DEPLOYMENTS=deployment/portal-js-${{ needs.metadata.outputs.docker-version }}" >> $GITHUB_ENV | |
echo "K8S_INGRESS_HOST=${{ needs.metadata.outputs.docker-version }}.portal-js.dev.eanadev.org" >> $GITHUB_ENV | |
- | |
name: Prepare env for test deployment | |
if: github.event_name == 'push' | |
run: | | |
echo "K8S_NAMESPACE=test" >> $GITHUB_ENV | |
echo "K8S_DEPLOYMENTS=deployment/portal-js deployment/ds4ch" >> $GITHUB_ENV | |
- | |
name: Create K8s resource manifests for dev deployments | |
if: github.event_name == 'pull_request' | |
run: | | |
envsubst < .github/workflows/support/ci/k8s/deployment.yml > deployment.yml | |
envsubst < .github/workflows/support/ci/k8s/service.yml > service.yml | |
envsubst < .github/workflows/support/ci/k8s/ingress.yml > ingress.yml | |
- | |
name: Install ibmcloud CLI | |
run: | | |
curl -fsSL https://clis.cloud.ibm.com/install/linux | sh | |
ibmcloud plugin install container-service | |
- | |
name: Login to IBM Cloud | |
run: | | |
ibmcloud login -a ${IBMCLOUD_API_URL} -r ${IBMCLOUD_REGION} --apikey ${IBMCLOUD_API_KEY} | |
ibmcloud ks cluster config --cluster ${IBMCLOUD_CLUSTER_NAME} | |
- | |
name: Detect new deployment | |
if: github.event_name == 'pull_request' | |
run: | | |
set +e | |
kubectl --namespace dev get ${K8S_DEPLOYMENTS} | |
if [ $? -eq 1 ]; then K8S_NEW_DEPLOYMENT="true"; else K8S_NEW_DEPLOYMENT="false"; fi | |
set -e | |
echo K8S_NEW_DEPLOYMENT=${K8S_NEW_DEPLOYMENT} >> $GITHUB_ENV | |
- | |
name: Create new dev resources on IBM Cloud K8s | |
if: github.event_name == 'pull_request' | |
run: | | |
kubectl apply -f deployment.yml | |
kubectl apply -f service.yml | |
kubectl apply -f ingress.yml | |
- | |
name: Restart deployment | |
run: kubectl rollout restart --namespace ${K8S_NAMESPACE} ${K8S_DEPLOYMENTS} | |
- | |
name: Comment with deployment link on pull request | |
if: env.K8S_NEW_DEPLOYMENT == 'true' | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: `Preview deployment: https://${process.env.K8S_INGRESS_HOST}/` | |
}) |