Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mrc 5976 - use github actions and ghcr #232

Merged
merged 52 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
20d9f2b
try with test jobs
M-Kusumgar Nov 7, 2024
13ab650
adding more into the action
M-Kusumgar Nov 7, 2024
12a9d3f
composite actions can only take strings?
M-Kusumgar Nov 7, 2024
db30122
better logic
M-Kusumgar Nov 7, 2024
33e67c9
disable playwright web server in config
M-Kusumgar Nov 7, 2024
f1256dd
split up backend and frontend tests
M-Kusumgar Nov 7, 2024
662c2d1
fix workflow tests and install playwright browsers
M-Kusumgar Nov 7, 2024
fa4afe1
try fully parallel tests
M-Kusumgar Nov 7, 2024
f8ebc09
cache playwright binaries and shard tests
M-Kusumgar Nov 7, 2024
8aad0a7
testing playwright cache
M-Kusumgar Nov 7, 2024
5e7e0ad
try to make stochastic less flaky
M-Kusumgar Nov 7, 2024
3f9f2a2
try and make tests less flaky
M-Kusumgar Nov 7, 2024
01e8f08
add build action
M-Kusumgar Nov 7, 2024
daceefa
full context
M-Kusumgar Nov 7, 2024
5718e8b
try original dockerfile
M-Kusumgar Nov 7, 2024
5fee2ed
clean up buildkite stuff
M-Kusumgar Nov 7, 2024
a1412a3
add codecov config to silence dumb failures
M-Kusumgar Nov 7, 2024
5a88d81
try 2% threshold
M-Kusumgar Nov 7, 2024
785e6c0
smoke test after build
M-Kusumgar Nov 7, 2024
b178401
proper smoke test
M-Kusumgar Nov 7, 2024
f94c773
wait for server for longer
M-Kusumgar Nov 7, 2024
a814d20
slower timing
M-Kusumgar Nov 7, 2024
b1fdd8a
get base image with node 20 from repo
M-Kusumgar Nov 7, 2024
6fccbb0
specify tag
M-Kusumgar Nov 7, 2024
ce8392e
split general action into multiple
M-Kusumgar Nov 16, 2024
8386fb9
emma changed: clean up code and better working
M-Kusumgar Nov 16, 2024
a581934
try pull manifest on github action
M-Kusumgar Dec 3, 2024
c89308f
try again
M-Kusumgar Dec 3, 2024
abb9581
space
M-Kusumgar Dec 3, 2024
0234f16
try with new token
M-Kusumgar Dec 3, 2024
d616c9e
now with auth
M-Kusumgar Dec 3, 2024
d531170
use double quotes instead of single quotyes
M-Kusumgar Dec 3, 2024
e71abda
add conditional step to make new docker image
M-Kusumgar Dec 3, 2024
6b2b5b1
just checking lint for now
M-Kusumgar Dec 3, 2024
bc92d1a
fix typo in curl
M-Kusumgar Dec 3, 2024
1ae4c4c
put all in single workflow
M-Kusumgar Dec 3, 2024
ee07278
test conditional
M-Kusumgar Dec 3, 2024
13e16fd
publish to latest tag if on main and testing is done
M-Kusumgar Dec 3, 2024
692968b
complete script
M-Kusumgar Dec 3, 2024
a0f73d6
rename to CI
M-Kusumgar Dec 3, 2024
b879ab1
consistent spacing
M-Kusumgar Dec 3, 2024
9611cb0
fix npm package install action + pull out stochastic logic into helper
M-Kusumgar Dec 3, 2024
4f39338
fix actions
M-Kusumgar Dec 3, 2024
7cf5ebb
npm i instead of ci
M-Kusumgar Dec 3, 2024
b68a5a8
install playwright first
M-Kusumgar Dec 3, 2024
c6fc9fb
ci instead of i
M-Kusumgar Dec 3, 2024
677e6d2
switch order again
M-Kusumgar Dec 3, 2024
715d0af
pin playwright version
M-Kusumgar Dec 3, 2024
a55a6b9
typo
M-Kusumgar Dec 3, 2024
63ac83e
testing current implementation
M-Kusumgar Dec 3, 2024
8b3c2ab
add checkout to publish job
M-Kusumgar Dec 3, 2024
5018d12
add comment and revert to main branch publishing
M-Kusumgar Dec 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Comment on lines -58 to -68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this needed any more? On CI it does build and run server so I guess don't need it there? But it's nice to not have to remember to run the app manually when running locally.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was pretty much never needed, the thing is we have to remember to run the app manually when running browser tests anyway, because doing an npm run dev/serve doesnt actually bring up our app, we have to also start our express server, i can include this in a later pr and only have this config if we are on local but we will have to run our build and run script or something like that

})
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
Loading