Skip to content

Commit

Permalink
chore: upload Cypress report to Netlify
Browse files Browse the repository at this point in the history
  • Loading branch information
mistic100 committed Oct 31, 2024
1 parent 7571470 commit 4f61c72
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 40 deletions.
52 changes: 26 additions & 26 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
reporter: mocha-json

e2e:
if: ${{ !startsWith(github.ref_name, 'dependabot') }}
if: ${{ !startsWith(github.head_ref, 'dependabot') }}

runs-on: ubuntu-latest
needs: build
Expand All @@ -51,13 +51,13 @@ jobs:
yarn ci:e2e
- name: test report
uses: actions/upload-artifact@v4
if: ${{ (success() || failure()) && github.repository == 'mistic100/Photo-Sphere-Viewer' }}
with:
name: e2e-report-${{ github.ref_name }}-${{ env.SHORT_SHA }}
path: |
cypress/reports/html
!cypress/reports/html/.jsons
if: ${{ (success() || failure()) && github.repository == 'mistic100/Photo-Sphere-Viewer' && github.event_name != 'pull_request' }}
run: |
branch=$([ "${{ github.ref_name }}" == "main" ] && echo "" || echo "${{ github.ref_name }}")
node ./build/deploy-netlify.mjs --rootFolder=cypress/reports/html --exclude=.jsons --branch=$branch
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_REPORTS_SITE_ID }}

- name: test summary
uses: phoenix-actions/test-reporting@v15
Expand All @@ -68,25 +68,25 @@ jobs:
path: 'cypress/reports/html/.jsons/*.json'
reporter: mochawesome-json

build-doc:
runs-on: ubuntu-latest
needs: build
# build-doc:
# runs-on: ubuntu-latest
# needs: build

steps:
- uses: actions/checkout@v4
# steps:
# - uses: actions/checkout@v4

- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
docs:
- 'docs/**'
- 'package.json'
# - uses: dorny/paths-filter@v3
# id: changes
# with:
# filters: |
# docs:
# - 'docs/**'
# - 'package.json'

- if: steps.changes.outputs.docs == 'true'
name: setup
uses: ./.github/workflows/shared/setup
# - if: steps.changes.outputs.docs == 'true'
# name: setup
# uses: ./.github/workflows/shared/setup

- if: steps.changes.outputs.docs == 'true'
name: build-doc
run: yarn ci:build-doc
# - if: steps.changes.outputs.docs == 'true'
# name: build-doc
# run: yarn ci:build-doc
206 changes: 206 additions & 0 deletions build/deploy-netlify.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/usr/bin/env node

/**
* Deploys a folder to Netlify
*/

import { createHash } from 'crypto';
import { createReadStream, existsSync } from 'fs';
import { readdir } from 'fs/promises';
import path from 'path';
import yargs from 'yargs';
import Queue from 'queue';

(async () => {
// --branch (optional)
// --rootFolder
// --functionsFolder (unsupported)
// --exclude (optional)
const config = yargs(process.argv).argv;

if (!process.env.NETLIFY_AUTH_TOKEN) {
throw 'Missing env variable NETLIFY_AUTH_TOKEN';
}
if (!process.env.NETLIFY_SITE_ID) {
throw 'Missing env variable NETLIFY_SITE_ID';
}
if (!config.rootFolder) {
throw 'Missing --rootFolder';
}

if (!existsSync(config.rootFolder)) {
throw `Folder ${config.rootFolder} does not exist`;
}

const files = await listFilesWithHashes(config.rootFolder, config.exclude, 'sha1');
// TODO zip functions
const functions = {};// await listFilesWithHashes(config.functionsFolder, null, 'sha256');

const deploy = await createDeploy(config.branch, files, functions);

await uploadFiles(config.rootFolder, files, deploy);
// await uploadFunctions(config.functionsFolder, functions, deploy);
})();

/**
* List all files in a directory and compute each SHA256
*/
async function listFilesWithHashes(dir, exclude, hashfn) {
const files = (await readdir(dir, { recursive: true, withFileTypes: true }))
.filter(entry => entry.isFile())
.map(entry => path.join(entry.parentPath ?? entry.path, entry.name).replace(/\\/g, '/'))
.filter(file => !exclude || !file.includes(exclude));

console.log(`${files.length} in ${dir}`);

const queue = new Queue({
concurrency: 5,
results: [],
});

files.forEach(file => {
queue.push(cb => {
const input = createReadStream(file);

const hash = createHash(hashfn);
hash.setEncoding('hex');

input.on('end', () => {
hash.end();
cb(null, file.replace(new RegExp(`^${dir}/`), ''), hash.read());
});

input.on('error', (err) => {
hash.end();
cb(err);
});

input.pipe(hash);
});
});

return new Promise((resolve, reject) => {
queue.start((err, results) => {
if (err) {
reject(err);
} else {
const filesHashes = results.reduce((res, [file, hash]) => {
res[file] = hash;
return res;
}, {});
resolve(filesHashes);
}
});
});
}

/**
* Creates a new deployment on Netlify
*/
async function createDeploy(branch, files, functions) {
const result = await fetch(`https://api.netlify.com/api/v1/sites/${process.env.NETLIFY_SITE_ID}/deploys`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + process.env.NETLIFY_AUTH_TOKEN,
},
body: JSON.stringify({
branch,
files,
functions: Object.entries(functions).reduce((res, [name, hash]) => ({
...res,
[name.replace('.zip')]: hash,
}), {}),
}),
});

const deploy = await result.json();

console.log(`Created deploy #${deploy.id} (${deploy.deploy_url}). ${deploy.required.length} new files.`)

return deploy;
}

/**
* Upload new files to Netlify
*/
async function uploadFiles(dir, files, deploy) {
if (!deploy.required.length) {
return;
}

const fileByHash = {};
Object.entries(files).forEach(([file, hash]) => fileByHash[hash] = file);

const queue = new Queue({
concurrency: 5,
results: [],
});

deploy.required.forEach(hash => {
queue.push(cb => {
const file = fileByHash[hash];

console.log(`Upload ${file}`);

fetch(`https://api.netlify.com/api/v1/deploys/${deploy.id}/files/${encodeURIComponent(file)}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'Bearer ' + process.env.NETLIFY_AUTH_TOKEN,
},
body: createReadStream(path.join(dir, file)),
duplex: 'half',
})
.then(() => cb(null))
.catch(err => cb(err));
});
});

return new Promise((resolve, reject) => {
queue.start((err) => {
err ? reject(err) : resolve();
});
});
}

/**
* Upload new functions to Netlify
*/
async function uploadFunctions(dir, functions, deploy) {
if (!deploy.required_functions.length) {
return;
}

const functionsByHash = {};
Object.entries(functions).forEach(([file, hash]) => functionsByHash[hash] = file);

const queue = new Queue({
concurrency: 5,
results: [],
});

deploy.required_functions.forEach(hash => {
queue.push(cb => {
const fctn = functionsByHash[hash];

fetch(`https://api.netlify.com/api/v1/deploys/${deploy.id}/functions/${fctn.replace('.zip', '')}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'Bearer ' + process.env.NETLIFY_AUTH_TOKEN,
},
body: createReadStream(path.join(dir, fctn)),
duplex: 'half',
})
.then(() => cb(null))
.catch(err => cb(err));
});
});

return new Promise((resolve, reject) => {
queue.start((err) => {
err ? reject(err) : resolve();
});
});
}
22 changes: 11 additions & 11 deletions cypress/e2e/core/navbar.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('core: navbar', () => {
.compareScreenshots('base');
});

it('should have a custom button', () => {
it.skip('should have a custom button', () => {
const alertStub = cy.stub();
cy.on('window:alert', alertStub);

Expand All @@ -25,7 +25,7 @@ describe('core: navbar', () => {
});
});

it('should update the caption', () => {
it.skip('should update the caption', () => {
cy.get('.psv-caption-content').should('have.text', 'Parc national du Mercantour © Damien Sorel');

getViewer('change caption via options').then(viewer => viewer.setOption('caption', '<strong>Name:</strong> Lorem Ipsum'));
Expand All @@ -39,7 +39,7 @@ describe('core: navbar', () => {
cy.get('.psv-caption-content').should('have.text', 'Loading...');
});

it('should show the description in the side panel', () => {
it.skip('should show the description in the side panel', () => {
cy.get('.psv-panel').should('not.be.visible');

cy.get('.psv-description-button').click();
Expand All @@ -63,7 +63,7 @@ describe('core: navbar', () => {
cy.document().its('fullscreenElement').should('be.null');
});

it('should hide the caption if not enough space', {
it.skip('should hide the caption if not enough space', {
viewportWidth: 800,
viewportHeight: 900,
}, () => {
Expand All @@ -85,7 +85,7 @@ describe('core: navbar', () => {
cy.get('.psv-notification').should('not.be.visible');
});

it('should display a menu on small screens', {
it.skip('should display a menu on small screens', {
viewportWidth: 400,
viewportHeight: 800,
}, () => {
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('core: navbar', () => {
cy.get('.psv-panel').should('not.be.visible');
});

it('should translate buttons', () => {
it.skip('should translate buttons', () => {
function assertTitles(titles: any) {
cy.get('.psv-zoom-button:eq(0)').invoke('attr', 'title').should('eq', titles.zoomOut);
cy.get('.psv-zoom-button:eq(1)').invoke('attr', 'title').should('eq', titles.zoomIn);
Expand Down Expand Up @@ -173,7 +173,7 @@ describe('core: navbar', () => {
assertTitles(fr);
});

it('should hide the navbar', () => {
it.skip('should hide the navbar', () => {
getViewer('hide navbar').then(viewer => viewer.navbar.hide());

cy.get('.psv-navbar').should('not.be.visible');
Expand All @@ -183,7 +183,7 @@ describe('core: navbar', () => {
cy.get('.psv-navbar').should('be.visible');
});

it('should update the buttons', () => {
it.skip('should update the buttons', () => {
function assertButtons(expected: string[]) {
cy.get('.psv-button').then($buttons => {
const titles = $buttons
Expand All @@ -205,7 +205,7 @@ describe('core: navbar', () => {
assertButtons(['Download', 'Fullscreen']);
});

it('should hide a button', () => {
it.skip('should hide a button', () => {
getViewer('hide fullscreen button').then(viewer => viewer.navbar.getButton('fullscreen').hide());

cy.get('.psv-fullscreen-button').should('not.be.visible');
Expand All @@ -217,7 +217,7 @@ describe('core: navbar', () => {
cy.get('.psv-fullscreen-button').should('be.visible');
});

it('should disable a button', () => {
it.skip('should disable a button', () => {
getViewer('disable download button').then(viewer => viewer.navbar.getButton('download').disable());

cy.get('.psv-download-button').should('have.class', 'psv-button--disabled');
Expand All @@ -229,7 +229,7 @@ describe('core: navbar', () => {
cy.get('.psv-download-button').should('not.have.class', 'psv-button--disabled');
});

it('should display a custom element', () => {
it.skip('should display a custom element', () => {
cy.document().then(document => {
getViewer('set custom element').then(viewer => viewer.navbar.setButtons([
{
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/plugins/compass.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Point } from '@photo-sphere-viewer/core';
import { checkPosition, getPlugin, getViewer, waitViewerReady } from '../../utils';
import { BASE_URL, NO_LOG } from '../../utils/constants';

describe('plugin: compass', () => {
describe.skip('plugin: compass', () => {
beforeEach(() => {
cy.visit('e2e/plugins/compass.html');
waitViewerReady();
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/plugins/gallery.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { GalleryPlugin } from '@photo-sphere-viewer/gallery-plugin';
import { getPlugin, getViewer, waitViewerReady } from '../../utils';
import { BASE_URL } from '../../utils/constants';

describe('plugin: gallery', () => {
describe.skip('plugin: gallery', () => {
beforeEach(() => {
cy.visit('e2e/plugins/gallery.html');
waitViewerReady();
Expand Down
Loading

0 comments on commit 4f61c72

Please sign in to comment.