Skip to content

Commit

Permalink
Fix packaging (#105)
Browse files Browse the repository at this point in the history
* Fix packaging the frontend
And test for isolated installation

* Update gitignore

* Fix workflow syntax

* Ignore log error for now

* Fix base-setup

* Lint the code

* Prettify

* Fix conda pkg installation

* Fix shell

* Fix availability of quetz-frontend packages

* Fix core path for building extension

* Create server config in well specified folder

* Use existing file for hash construction
  • Loading branch information
fcollonval authored Mar 17, 2022
1 parent fd2a1c1 commit abd1fe6
Show file tree
Hide file tree
Showing 16 changed files with 1,115 additions and 65 deletions.
9 changes: 4 additions & 5 deletions .github/actions/base-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ runs:
with:
environment-name: quetz
environment-file: ${{ inputs.server_folder }}/environment.yml

- name: Install Node.js
shell: bash -l {0}
run: |
conda install nodejs=14 yarn
extra-specs: |
nodejs=16
yarn
cache-downloads: true

- name: Install the server
shell: bash -l {0}
Expand Down
114 changes: 108 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ on:
jobs:
build:
runs-on: ubuntu-latest

defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v2
with:
Expand All @@ -25,27 +30,94 @@ jobs:
yarn run eslint:check
yarn run prettier:check
- name: Install builder
run: |
conda install build
- name: Package frontend
working-directory: frontend
run: |
set -ex
python -m build -w .
- name: Upload package
uses: actions/upload-artifact@v2
with:
name: quetz-frontend-wheel
path: frontend/dist/quetz_frontend*.whl
if-no-files-found: error

example:
name: Test Quetz frontend extension examples
runs-on: ubuntu-latest
needs: build

defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
path: frontend
name: quetz-frontend-wheel

- name: Base Setup
uses: ./frontend/.github/actions/base-setup
- run: |
cat > environment.yml << EOF
name: quetz
channels:
- https://repo.mamba.pm/conda-forge
dependencies:
- python>=3.7
- nodejs=16
- yarn
EOF
- uses: mamba-org/provision-with-micromamba@main
with:
frontend_folder: frontend
environment-name: quetz
environment-file: environment.yml
cache-downloads: true

- name: Base Setup
run: |
set -ex
pip install quetz_frontend*.whl
# FIXME missing quetz server dependency
pip install "httpx~=0.20.0"
cat > dev_config.toml << EOF
[sqlalchemy]
database_url = "sqlite:///./quetz.sqlite"
[session]
secret = "b72376b88e6f249cb0921052ea8a092381ca17fd8bb0caf4d847e337b3d34cf8"
https_only = false
[logging]
level = "DEBUG"
file = "quetz.log"
[users]
admins = ["dummy:alice"]
EOF
quetz create --copy-conf ./dev_config.toml --dev /tmp/test_quetz
- uses: actions/checkout@v2

- name: Build quetz packages
run: |
set -ex
yarn
yarn build:packages
- name: Install
working-directory: frontend/examples/light_theme
working-directory: examples/light_theme
run: |
set -ex
yarn
# Build first so it link with local version of @quetz-frontend packages
yarn build
Expand All @@ -55,3 +127,33 @@ jobs:
quetz-frontend list
quetz-frontend list 2>&1 | grep -ie "@quetz-example/light-theme"
- name: Set up browser cache
uses: actions/cache@v2
with:
path: |
${{ github.workspace }}/pw-browsers
key: ${{ runner.os }}-${{ hashFiles('examples/tests/package.json') }}

- name: Install Playwright
working-directory: examples/tests
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
run: |
set -ex
yarn
yarn playwright install chromium
- name: Test example
working-directory: examples/tests
run: |
set -ex
yarn test
- name: Upload Playwright Test report
if: always()
uses: actions/upload-artifact@v2
with:
name: light-theme-playwright-tests
path: |
examples/tests/test-results
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ junit.xml
*.code-workspace
.history
.vscode
examples/tests/test_quetz
5 changes: 2 additions & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ include ts*.json
include yarn.lock
include lerna.json

graft quetz_frontend/app/
graft quetz_frontend/app
graft packages

prune quetz_frontend/app/build
prune **/node_modules
# prune lib
# prune binder

# Patterns to exclude from any directory
global-exclude *~
Expand Down
46 changes: 46 additions & 0 deletions examples/tests/example.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ConsoleMessage, expect, test } from '@playwright/test';

test.beforeEach(async ({ page }) => {
await Promise.all([
page.waitForNavigation({
url: (url) => url.pathname === '/',
}),
page.goto('/api/dummylogin/alice'),
]);
});

test('should load the example', async ({ baseURL, page }) => {
const URL = process.env['BASE_URL'] ?? baseURL;
console.info('Navigating to page:', URL);

let errorLogs = 0;
let testEnded: (value: string | PromiseLike<string>) => void;
const waitForTestEnd = new Promise<string>((resolve) => {
testEnded = resolve;
});

const handleMessage = async (msg: ConsoleMessage) => {
const text = msg.text();
console.log(msg.type(), '>>', text);
if (msg.type() === 'error') {
errorLogs += 1;
}

const lower = text.toLowerCase();
// An extension example must emit a console log message ending by `is activated!`
if (/is activated!$/.test(lower)) {
testEnded(text);
}
};

page.on('console', handleMessage);

await page.goto(URL);

await expect(page.locator('#jupyter-config-data')).toBeDefined();

await waitForTestEnd;

// FIXME some errors are occurring
// await expect(errorLogs).toEqual(0);
});
13 changes: 13 additions & 0 deletions examples/tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@quetz-frontend/examples-test",
"version": "1.0.0",
"description": "Quetz Frontend Examples Tests",
"private": true,
"scripts": {
"start": "quetz start /tmp/test_quetz",
"test": "yarn playwright test"
},
"devDependencies": {
"@playwright/test": "^1.19.0"
}
}
33 changes: 33 additions & 0 deletions examples/tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { PlaywrightTestConfig, devices } from '@playwright/test';

const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,
retries: 0,
webServer: {
command: 'yarn run start',
port: 8000,
timeout: 120 * 1000,
// It is safe to reuse the server for stories testing
reuseExistingServer: true,
},
use: {
baseURL: process.env.TARGET_URL ?? 'http://localhost:8000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] }
// },
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] }
// }
],
};

export default config;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
"scripts": {
"build": "yarn run build:packages && yarn run build:core",
"build:core": "cd quetz_frontend/app && yarn && yarn run build",
"build:core:prod": "cd quetz_frontend/app && yarn && yarn run build:prod",
"build:examples": "lerna run build --scope \"@quetz-example/*\"",
"build:packages": "lerna run build --scope \"@quetz-frontend/!(main-app)*\"",
"build:prod": "yarn run build:packages && yarn run build:core",
"build:prod": "yarn run build:packages && yarn run build:core:prod",
"clean": "yarn run clean:core && yarn run clean:packages",
"clean:all": "lerna run clean:all && rimraf yarn.lock && rimraf node_modules",
"clean:core": "cd quetz_frontend/app && yarn run clean",
Expand Down
3 changes: 3 additions & 0 deletions packages/menu-extension/src/title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ function activateTitle(app: QuetzFrontEnd, router: IRouter): void {
spacer.addClass('topbar-spacer');
app.shell.add(spacer, 'top', { rank: 50 });

/**
* Create the Quetz Logo widget
*/
function createLogo(): Widget {
const link = document.createElement('a');
const logo = new Widget({ node: link });
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ requires = ["jupyter_packaging~=0.10,<2"]
build-backend = "jupyter_packaging.build_api"

[tool.jupyter-packaging.options]
skip-if-exists = ["quetz_frontend/app/style.js"]
ensured-targets = ["quetz_frontend/app/style.js", "quetz_frontend/app/package.json"]
skip-if-exists = ["quetz_frontend/app/static/style.js"]
ensured-targets = ["quetz_frontend/app/static/style.js", "quetz_frontend/app/static/package.json"]

[tool.jupyter-packaging.builder]
factory = "jupyter_packaging.npm_builder"
Expand Down
42 changes: 42 additions & 0 deletions quetz_frontend/app/webpack.prod.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const TerserPlugin = require('terser-webpack-plugin');
const merge = require('webpack-merge').default;
const WPPlugin = require('@quetz-frontend/builder').WPPlugin;
const config = require('./webpack.config');

config[0] = merge(config[0], {
mode: 'production',
devtool: false, // 'source-map',
output: {
// Add version argument when in production so the Jupyter server
// allows caching of files (i.e., does not set the CacheControl header to no-cache to prevent caching static files)
filename: '[name].[contenthash].js?v=[contenthash]',
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
sourceMap: true,
terserOptions: {
compress: false,
ecma: 6,
mangle: true,
output: {
beautify: false,
comments: false,
},
safari10: true,
},
cache: process.platform !== 'win32',
}),
],
},
plugins: [
new WPPlugin.JSONLicenseWebpackPlugin({
excludedPackageTest: (packageName) =>
packageName === '@quetz-frontend/main-app',
}),
],
});

module.exports = config;
Loading

0 comments on commit abd1fe6

Please sign in to comment.