Skip to content

Commit

Permalink
Merge pull request #232 from mrc-ide/mrc-5976
Browse files Browse the repository at this point in the history
Mrc 5976 - use github actions and ghcr
  • Loading branch information
M-Kusumgar authored Dec 5, 2024
2 parents ab2d031 + 5018d12 commit 928366b
Show file tree
Hide file tree
Showing 20 changed files with 270 additions and 203 deletions.
15 changes: 15 additions & 0 deletions .github/actions/build-and-run-wodin/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Build and run WODIN (and deps)

runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: 20

- name: Build and run server
shell: bash
run: |
./scripts/build.sh
./scripts/run-dependencies.sh
npm run serve --prefix=app/server &
39 changes: 39 additions & 0 deletions .github/actions/ci-env-and-ghcr-login/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Setup CI Env and login to GHCR

inputs:
ghcr-username:
required: true
ghcr-password:
required: true

outputs:
CI_SHA:
description: "Short SHA of current commit"
value: ${{ steps.ci-env.outputs.CI_SHA }}
CI_BRANCH:
description: "Current branch"
value: ${{ steps.ci-env.outputs.CI_BRANCH }}

runs:
using: "composite"
steps:
- id: ci-env
name: Setup Environment
shell: bash
run: |
if [ "${{github.event_name}}" = "pull_request" ];
then
long_sha=${{ github.event.pull_request.head.sha }}
echo "CI_BRANCH=${{ github.head_ref }}" >> $GITHUB_OUTPUT
else
long_sha=${GITHUB_SHA}
echo "CI_BRANCH=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi
echo "CI_SHA=${long_sha:0:7}" >> $GITHUB_OUTPUT
- name: Login to GHCR (GitHub Packages)
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ inputs.ghcr-username }}
password: ${{ inputs.ghcr-password }}
28 changes: 28 additions & 0 deletions .github/actions/install-npm-packages/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Install NPM packages

inputs:
server:
required: false
default: 'false'
static:
required: false
default: 'false'

runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: 20

- name: Install server (backend) NPM packages
if: inputs.server == 'true'
shell: bash
run: |
npm ci --prefix=app/server
- name: Install static (frontend) NPM packages
if: inputs.static == 'true'
shell: bash
run: |
npm ci --prefix=app/static
135 changes: 135 additions & 0 deletions .github/workflows/build-test-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: CI

on: [push]

env:
TAG_GHCR: mrc-ide/wodin

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: ci-env
uses: ./.github/actions/ci-env-and-ghcr-login
with:
ghcr-username: ${{ github.actor }}
ghcr-password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push docker
uses: docker/build-push-action@v5
with:
file: ./docker/Dockerfile
push: true
tags: |
ghcr.io/${{ env.TAG_GHCR }}:${{ steps.ci-env.outputs.CI_SHA }}
ghcr.io/${{ env.TAG_GHCR }}:${{ steps.ci-env.outputs.CI_BRANCH }}
- name: Smoke test
run: |
./scripts/run-version.sh --app ${{ steps.ci-env.outputs.CI_BRANCH }} &
./scripts/smoke-test.sh
fe-unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/install-npm-packages
with:
static: true

- name: Test front end
run: npm run coverage --prefix=app/static
- uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
files: ./app/static/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
codecov_yml_path: ./codecov.yml

be-unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-and-run-wodin

- name: Test back end
run: npm test --prefix=app/server
- name: Check versions
run: npm run genversion --prefix=app/server -- --check-only
- uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true # optional (default = false)
files: ./app/server/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }} # required

integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-and-run-wodin

- name: Test back end integration
run: npm run integration-test --prefix=app/server

playwright-tests:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4, 5, 6]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-and-run-wodin

- name: Get installed Playwright version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./app/static/package-lock.json').packages['node_modules/@playwright/test'].version)")" >> $GITHUB_ENV
- name: Cache binaries for playwright version
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Install Playwright Browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright@${{ env.PLAYWRIGHT_VERSION }} install --with-deps
- name: Test e2e
run: npm run test:e2e --prefix=app/static -- --shard=${{ matrix.shard }}/6

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/install-npm-packages
with:
static: true
server: true

- name: Lint back end
run: npm run lint --prefix=app/server
- name: Lint front end
run: npm run lint --prefix=app/static

publish-latest-image:
runs-on: ubuntu-latest
# change this ref to publish to "latest" tag from another branch
if: github.ref == 'refs/heads/main'
needs: [build-and-push, fe-unit-tests, be-unit-tests, integration-tests, playwright-tests, lint]
steps:
- uses: actions/checkout@v4
- id: ci-env
uses: ./.github/actions/ci-env-and-ghcr-login
with:
ghcr-username: ${{ github.actor }}
ghcr-password: ${{ secrets.GITHUB_TOKEN }}

- name: Publish image manifest to latest
run: |
GHCR_TOKEN=$(echo ${{ secrets.GITHUB_TOKEN }} | base64)
curl "https://ghcr.io/v2/mrc-ide/wodin/manifests/${{ steps.ci-env.outputs.CI_BRANCH }}" \
-H "accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Bearer ${GHCR_TOKEN}" \
> manifest.json
curl -XPUT "https://ghcr.io/v2/mrc-ide/wodin/manifests/latest" \
-H "content-type: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Bearer ${GHCR_TOKEN}" \
-d '@manifest.json'
35 changes: 0 additions & 35 deletions .github/workflows/test.yml

This file was deleted.

15 changes: 1 addition & 14 deletions app/static/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ export default defineConfig({
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 1,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
fullyParallel: true,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
// reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
Expand All @@ -54,16 +53,4 @@ export default defineConfig({

/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',

/* Run your local dev server before starting the tests */
webServer: {
/**
* Use the dev server by default for faster feedback loop.
* Use the preview server on CI for more realistic testing.
* Playwright will re-use the local server if there is already a dev-server running.
*/
command: process.env.CI ? 'npm run build' : 'npm run dev',
port: 5173,
reuseExistingServer: !process.env.CI
}
})
11 changes: 6 additions & 5 deletions app/static/tests/e2e/index.etest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ import * as fs from "fs";
import { realisticFitData } from "./utils";

test.describe("Index tests", () => {
const tmpPath = "tmp";
let tmpPath: string;

test.beforeAll(() => {
test.beforeEach(() => {
tmpPath = `${Math.random()}`;
if (fs.existsSync(tmpPath)) {
fs.rmdirSync(tmpPath, { recursive: true });
fs.rmSync(tmpPath, { recursive: true });
}
fs.mkdirSync(tmpPath);
});

test.afterAll(() => {
fs.rmdirSync(tmpPath, { recursive: true });
test.afterEach(() => {
fs.rmSync(tmpPath, { recursive: true });
});

test("renders heading", async ({ page }) => {
Expand Down
46 changes: 16 additions & 30 deletions app/static/tests/e2e/stochastic.etest.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { expect, test } from "@playwright/test";
import PlaywrightConfig from "../../playwright.config";
import { expect, Page, test } from "@playwright/test";
import { expectSummaryValues } from "./utils";

test.describe("stochastic app", () => {
const { timeout } = PlaywrightConfig;

test.beforeEach(async ({ page }) => {
await page.goto("/apps/day3");
await page.click(":nth-match(.wodin-left .nav-tabs a, 2)"); // Options
await page.click(":nth-match(.wodin-right .nav-tabs a, 2)"); // Run
});

const expectChangedNumberOfReplicatesMessage = async (page: Page, newReplicates: string) => {
await expect(await page.locator(".action-required-msg")).toHaveText("");
await page.fill(":nth-match(#run-options input, 2)", newReplicates);
await expect(await page.locator(".action-required-msg")).toHaveText(
"Plot is out of date: number of replicates has changed. Run model to update."
);
};

test("can display number of replicates", async ({ page }) => {
await expect(await page.innerText(":nth-match(.collapse-title, 2)")).toContain("Run Options");
await expect(await page.getAttribute(":nth-match(.collapse-title i, 2)", "data-name")).toBe("chevron-up");
Expand All @@ -22,18 +27,11 @@ test.describe("stochastic app", () => {
});

test("can change number of replicates and re-run model", async ({ page }) => {
await page.fill(":nth-match(#run-options input, 2)", "6");

await expect(await page.locator(".run-tab .action-required-msg")).toHaveText(
"Plot is out of date: number of replicates has changed. Run model to update.",
{
timeout
}
);
await expectChangedNumberOfReplicatesMessage(page, "6");

// Re-run model
await page.click("#run-btn");
await expect(await page.locator(".run-tab .action-required-msg")).toHaveText("");
await expect(await page.locator(".action-required-msg")).toHaveText("");

// number of series should have increased by 2
const summary = ".wodin-plot-data-summary-series";
Expand All @@ -48,30 +46,18 @@ test.describe("stochastic app", () => {
});

test("traces are hidden if replicates are above maxReplicatesDisplay", async ({ page }) => {
await page.fill(":nth-match(#run-options input, 2)", "50");
await expect(await page.locator(".run-tab .action-required-msg")).toHaveText(
"Plot is out of date: number of replicates has changed. Run model to update.",
{
timeout
}
);
await expectChangedNumberOfReplicatesMessage(page, "50");

await page.click("#run-btn");
await expect(await page.locator(".run-tab .action-required-msg")).toHaveText("");
await expect(await page.locator(".action-required-msg")).toHaveText("");

const summary = ".wodin-plot-data-summary-series";
expect(await page.locator(summary).count()).toBe(104);

await page.fill(":nth-match(#run-options input, 2)", "51");
await expect(await page.locator(".run-tab .action-required-msg")).toHaveText(
"Plot is out of date: number of replicates has changed. Run model to update.",
{
timeout
}
);
await expectChangedNumberOfReplicatesMessage(page, "51");

await page.click("#run-btn");
await expect(await page.locator(".run-tab .action-required-msg")).toHaveText("");
await expect(await page.locator(".action-required-msg")).toHaveText("");

expect(await page.locator(summary).count()).toBe(4);

Expand All @@ -93,7 +79,7 @@ test.describe("stochastic app", () => {

// Can see summary traces
const summary = ".wodin-plot-data-summary-series";
await expect(await page.locator(summary)).toHaveCount(44, { timeout });
await expect(await page.locator(summary)).toHaveCount(44);

await expectSummaryValues(page, 1, "I_det (beta=0.450)", 1001, "#2e5cb8");
await expectSummaryValues(page, 2, "I (beta=0.450)", 1001, "#6ab74d");
Expand Down
Loading

0 comments on commit 928366b

Please sign in to comment.