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 9d3e3a7
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 8 deletions.
16 changes: 8 additions & 8 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 Down
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();
});
});
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"mocha-junit-reporter": "^2.2.1",
"postcss": "^8.4.21",
"prettier": "^2.8.8",
"queue": "^7.0.0",
"scss-bundle": "^3.1.2",
"selfsigned": "^2.4.1",
"set-versions": "^1.0.3",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4654,6 +4654,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==

queue@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/queue/-/queue-7.0.0.tgz#2f43841ac492a4848007089810702704f5b2c4ae"
integrity sha512-sphwS7HdfQnvrJAXUNAUgpf9H/546IE3p/5Lf2jr71O4udEYlqAhkevykumas2FYuMkX/29JMOgrRdRoYZ/X9w==

quick-lru@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
Expand Down

0 comments on commit 9d3e3a7

Please sign in to comment.