#!/usr/bin/env node /** * Run on Github by commits to master, this script: * 1. Gets all projects with a fleek configuration file * 2. Gets the last commit for the relevant site id * 3. Runs nx:affected for that commit ID and checks if the site has changed * 4. Calls deploy if it has * * This would probably be best as an NX task, but the circular nature of getting * the fleek ID for the project, then checking if it was affected didn't fit within the * build-only-affected cycle, and as each fleek deploy will have been triggered by * a different commit, it seemed best to do this outwith nx. Feel free to re-implement * this if the assumptions are wrong. * * It has also been written to skip external dependencies. */ const { existsSync, readdirSync, lstatSync, readFileSync } = require('fs'); const { execSync } = require('child_process'); /** * Parses the last commit hash out of the Fleek API response * @param {String} siteId * @returns string Last commit that triggered a build */ function getFleekLastBuildCommit(siteId) { const curl = `curl 'https://api.fleek.co/graphql' --silent -X POST -H 'Accept: */*' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Authorization: ${process.env['FLEEK_API_KEY']}' --data-raw '{"query":"{getSiteById(siteId: \\"${siteId}\\"){publishedDeploy{repository{commit}}}}","variables":null}'`; const fleekRes = execSync(curl); const res = JSON.parse(fleekRes.toString()); let commit = res.data.getSiteById.publishedDeploy.repository.commit; return commit; } /** * Triggers a Fleek build of the latest code via GraphQL * @param {String} siteId * @returns */ function triggerDeploy(siteId) { const curl = `curl 'https://api.fleek.co/graphql' --silent -X POST -H 'Accept: */*' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Authorization: ${process.env['FLEEK_API_KEY']}' --data-raw '{"query":"mutation {triggerDeploy(commit: \\"HEAD\\", siteId: \\"${siteId}\\"){status}}","variables":null}'`; const fleekRes = execSync(curl); const res = JSON.parse(fleekRes.toString()); // Will have thrown if it failed return true; } // The folder containing NX projects const projectPath = './apps/'; // The Fleek project file, the existence indicates a deployed app const fleekFile = '.fleek.json'; // Some simple stats for the end let fleekProjects = 0; let deployedProjects = 0; // Fleek CLI requires this variable to be set if (!process.env['FLEEK_API_KEY']) { console.error('Error: FLEEK_API_KEY must be set'); process.exit(1); } readdirSync(projectPath).forEach((proj) => { try { const project = `${projectPath}${proj}`; if (!lstatSync(project).isDirectory()) { // It's not a project folder, skip it return; } const config = `${project}/${fleekFile}`; if (!existsSync(config)) { // No fleek file, skip it return; } fleekProjects++; console.group(proj); // The UID for the site according to the config let siteId; try { const fleekConfig = JSON.parse(readFileSync(config)); siteId = fleekConfig.site.id; console.log(`Fleek site ID: ${siteId}`); } catch (e) { console.error(`Failed to read Fleek site id for ${proj}`); return; } // The last commit that triggered a build let baseCommit; try { baseCommit = getFleekLastBuildCommit(siteId); console.log(`Last deploy: ${baseCommit}`); } catch (e) { console.error(`Failed to fetch last deploy for ${proj}`); return; } // Now run nx affected let isAffected; try { const affectedSinceCommit = execSync( `yarn nx print-affected --base=${baseCommit} --head=master --select=projects` ); isAffected = affectedSinceCommit.toString().indexOf(proj) !== -1; } catch (e) { console.error(`Failed to run nx:affected for ${baseCommit}:master`); return; } if (isAffected) { console.log(`Triggering deploy for: ${siteId}`); deployedProjects++; try { triggerDeploy(siteId); } catch (e) { console.error(`Failed to trigger deploy for ${proj}`); process.exit(1); } } else { console.log(`Has not changed since last build, skipping...`); } console.groupEnd(); } catch (e) { console.log(e); process.exit(1); } }); console.log(`Fleek projects: ${fleekProjects}`); console.log(`Deploys triggered: ${deployedProjects}`); process.exit(0);