Skip to content

Commit

Permalink
(#402) Enhance local choco-theme development
Browse files Browse the repository at this point in the history
A sweet of commands have been added to the
`package.json` file to help with local development
of the choco-theme. All commands and explanations
can be found in the updated `README.md` file.

The changes here will help the developer
experience when working on choco-theme.
  • Loading branch information
st3phhays committed May 9, 2024
1 parent b4f1d08 commit 0ecc652
Show file tree
Hide file tree
Showing 26 changed files with 7,847 additions and 104 deletions.
52 changes: 45 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,51 @@ This repository holds all of the CSS, JS, images, and shared partial files that

Before running any commands below, ensure you have ran `yarn` in the root of this repository, and have enabled corepack by running `corepack enable`.

| Script | Action |
|-------------------------------------------------|----------------------------------------------------------------------------------------|
| yarn build | Builds CSS, JS, and Partials. |
| yarn lint | Runs Stylelint and ESLint to determine code style errors. |
| yarn change-version OLD_VERSION NEW_VERSION | Runs all build steps and updates choco-theme to the version specified. |
| yarn watch | Watches for changes in CSS, JS, and Partials, and rebuilds them automatically. |
| yarn npm audit | Audits packages and reports vulnerabilities. |
| Script | Action |
|-------------------------------------------------|-----------------------------------------------------------------------------------------------|
| yarn build | Builds CSS, JS, and Partials. |
| yarn change-version OLD_VERSION NEW_VERSION | Runs all build steps and updates choco-theme to the version specified. |
| yarn lint | Runs Stylelint and ESLint to determine code style errors. |
| yarn monitor-ports | Opens a page to monitor preview ports and report their status. |
| yarn npm audit | Audits packages and reports vulnerabilities. |
| yarn preview --PROJECT_NAME | Runs the preview script in desired repositories all at once for easy testing and development. |
| yarn preview-link --PROJECT_NAME | Links choco-theme locally to desired repositories for local development. |
| yarn preview-unlink --PROJECT_NAME | Unlinks choco-theme and restores the packages.json and yarn.lock files. |
| yarn preview-upgrade NEW_VERSION --PROJECT_NAME | Updates choco-theme to the specified version in desired repositories. |
| yarn preview-watch --PROJECT_NAME | Runs `yarn build` and `yarn-choco-theme` on desired repositories. |
| yarn watch | Watches for changes in CSS, JS, and Partials, and rebuilds them automatically. |

## Repository Project Names for Previewing

The below options are used in the commands above that contain a `preview` keyword, and require a `--PROJECT NAME`.

| --PROJECT_NAME | Suggested Cloned Folder Name |
|----------------|------------------------------|
| --blog | blog |
| --boxstarter | boxstarter.org |
| --community | community.chocolatey.org |
| --design | choco-design-system |
| --docs | docs |
| --fest | chocolateyfest |
| --org | chocolatey.org |
| --portal | licensing-services |
| --zendesk | copenhagen_theme |
| --all | Runs all above |

## Previewing Repositories for Local Development

When developing choco-them locally, there is a need to run multiple websites at once that live in different repositories. Follow the steps below to bring them up all at once, and enable live updating of choco-theme:

1. Ensure you have the repositories cloned down to your local machine and at the same root level as the choco-theme repository.
2. On each repository, it is a good idea to checkout a new branch with the same branch name, to keep track of progress easier.
3. To link each repository to your local instance of choco-theme, run `yarn preview-link --PROJECT_NAME`, for example `yarn preview-link --org --blog`.
1. Before doing this, ensure that your cloned folder names match that in the file located at `choco-theme/build/data/preview-config.ts`. If they do not, you will need to either:
1. Change the names of your folders or,
2. Update the `preview-config.ts` file to your folder names, but do not commit the file.
3. To enable choco-theme to build on demand and place files in repositories, run the command `yarn preview-watch --PROJECT_NAME`, for example `yarn preview-watch --org --blog`.
4. To bring up each website, in a new command window, run the command `yarn preview --PROJECT_NAME`, for example `yarn preview --org --blog`. This will bring up a directory webpage where you can easily monitor each port and navigate to them.

With the steps above done, any changes you make to your local instance of choco-theme, or the linked repositories, will trigger choco-theme to rebuild, and then rebuild the repositories automatically.

## Install ESLint Extension

Expand Down
17 changes: 17 additions & 0 deletions build/data/console-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env ts-node

/*!
* Colors that are used in the terminal while running choco-theme commands.
* Copyright 2020-2024 Chocolatey Software
* Licensed under Apache License (https://github.com/chocolatey/choco-theme/blob/main/LICENSE)
*/

export const revert = '\x1b[0m';
export const green = '\x1b[32m';
export const red = '\x1b[31m';

export const consoleColors = {
revert,
green,
red
};
67 changes: 67 additions & 0 deletions build/data/preview-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env ts-node

/*!
* Configuration for repositories to be used by preview commands.
* Copyright 2020-2024 Chocolatey Software
* Licensed under Apache License (https://github.com/chocolatey/choco-theme/blob/main/LICENSE)
*/

export interface FolderMapping {
[key: string]: {
folder: string;
protocol?: string;
port?: null | number;
isStatic: boolean;
root?: string
};
}

export const folderMapping: FolderMapping = {
'--blog': {
folder: 'blog',
port: 5082,
isStatic: true
},
'--boxstarter': {
folder: 'boxstarter.org',
port: 5083,
isStatic: true
},
'--community': {
folder: 'community.chocolatey.org',
port: 55881,
isStatic: false,
root: '/chocolatey/Website'
},
'--design': {
folder: 'choco-design-system',
port: 5085,
isStatic: true
},
'--docs': {
folder: 'docs',
port: 5086,
isStatic: true
},
'--fest': {
folder: 'chocolateyfest',
port: 5084,
isStatic: true
},
'--org': {
folder: 'chocolatey.org',
port: 5081,
isStatic: true
},
'--portal': {
folder: 'licensing-services',
protocol: 'https',
port: 44362,
isStatic: false,
root: '/source/LicensingServices'
},
'--zendesk': {
folder: 'copenhagen_theme',
isStatic: false
}
};
16 changes: 16 additions & 0 deletions build/functions/loading-animation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env ts-node

/*!
* Loading animation to be used in the terminal when running choco-theme commands.
* Copyright 2020-2024 Chocolatey Software
* Licensed under Apache License (https://github.com/chocolatey/choco-theme/blob/main/LICENSE)
*/

export const loadingAnimation = () => {
const frames = ['-', '\\', '|', '/'];
let i = 0;
return setInterval(() => {
process.stdout.write(`\r${frames[i]} Loading...`);
i = (i + 1) % frames.length;
}, 100);
};
85 changes: 85 additions & 0 deletions build/monitor-ports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env ts-node

/*!
* Script to start the preview server and monitor the ports of the repositories.
* Copyright 2020-2024 Chocolatey Software
* Licensed under Apache License (https://github.com/chocolatey/choco-theme/blob/main/LICENSE)
*/

import net, { Socket } from 'net';
import { spawn } from 'child_process';
import WebSocket, { WebSocketServer } from 'ws';
import { folderMapping } from './data/preview-config';

// List of ports to monitor
// Ensures if the folderMapping doesn't contain a port, that is excluded
const portList: number[] = Object.values(folderMapping)
.map(item => item.port)
.filter(port => port !== undefined);

const childProcess = spawn('yarn dlx http-server --cors -o', [], {
stdio: 'inherit', // sends info over to preview.ts to be read
shell: true
});

// Create a WebSocket server
const wss = new WebSocketServer({ port: 8081 });

// Function to check port status
const checkPortStatus = (port: number): Promise<string> => {
return new Promise((resolve, reject) => {
const socket: Socket = net.createConnection({ port }, () => {
socket.end();
resolve('open');
});

socket.on('error', err => {
const errorCodeMatch = err.message.match(/(EADDRINUSE|E.*):/);
const errorCode = errorCodeMatch ? errorCodeMatch[1] : null;

if (errorCode === 'ECONNREFUSED') {
resolve('closed');
} else {
reject(err);
}
});

socket.setTimeout(1000, () => {
socket.destroy();
resolve('in use');
});
});
};

// Function to monitor ports and send status to client
const monitorPorts = async (): Promise<void> => {
const portStatus: { [key: number]: string } = {};

for (const port of portList) {
try {
const status: string = await checkPortStatus(port);
portStatus[port] = status;
console.log(`Port ${port} is ${status}`);
} catch (err) {
// console.error(`Error checking port ${port}: ${(err as Error).message}`);
// Send port status to connected clients
console.log(`Port ${port} is closed`);
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
const portStatus = JSON.stringify({ [port]: 'closed' });
client.send(portStatus);
}
});
}
}

// Send port status to connected clients
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(portStatus));
}
});
};

// Start monitoring ports
setInterval(monitorPorts, 5000); // Check ports every 5 seconds
86 changes: 86 additions & 0 deletions build/preview-choco-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env ts-node

/*!
* Script to run choco-theme on specified linked folders.
* Copyright 2020-2024 Chocolatey Software
* Licensed under Apache License (https://github.com/chocolatey/choco-theme/blob/main/LICENSE)
*/

import * as fs from 'fs/promises';
import * as path from 'path';
import { spawn } from 'child_process';

import { folderMapping } from './data/preview-config';
import { loadingAnimation } from './functions/loading-animation';

const init = async () => {
// Parse command-line arguments
let args = process.argv.slice(2);

if (args[0] === '--all') {
args = Object.keys(folderMapping);
}

const foldersToRun = args.filter(arg => folderMapping[arg]);

if (foldersToRun.length === 0) {
console.error('Please specify at least one valid option.');
process.exit(1);
} else {
console.log('🚀 Running choco-theme on folders...');
}

// Array to store loading intervals for each script
const loadingIntervals = foldersToRun.map(() => loadingAnimation());

await Promise.all(foldersToRun.map(async (option, index) => {
const folderConfig = folderMapping[option];
const folderName = folderConfig.folder;
const folderNamePath = folderConfig.root ? `${folderName}${folderConfig.root}` : folderName;
const folderPath = path.join(__dirname, '../../', folderNamePath);

// Check if folder exists
try {
await fs.access(folderPath);
} catch (error) {
clearInterval(loadingIntervals[index]);
process.stdout.write('\r🟨 ');
console.log(`🟨 ${folderName} does not exist. Skipping...`);
return; // Skip to the next folder
}

try {
const childProcess = spawn('yarn choco-theme', [], {
// stdio: 'inherit', // Use 'inherit' to directly pipe the output to the parent process
shell: true, // Needed for Windows to execute .sh files
cwd: folderPath // Specify the working directory for the child process
});

// Handle stdout data event
childProcess.stdout.on('data', data => {
const output = data.toString().trim();
if (output.includes('🎉 choco-theme complete' || output.startsWith('[nodemon] restarting due to changes...'))) {
// Stop loading animation for this script
clearInterval(loadingIntervals[index]);
process.stdout.write('\r✅ ');
console.log(`choco-theme complete on ${folderName}`);
}
});

// Handle exit event
childProcess.on('exit', code => {
if (code !== 0) {
clearInterval(loadingIntervals[index]);
process.stdout.write('\r⛔ ');
console.error(`choco-theme not ran on ${folderName} and exited with code ${code}`);
}
});
} catch (error) {
clearInterval(loadingIntervals[index]);
process.stdout.write('\r⛔ ');
console.error(`choco-theme not ran on ${folderName}. Error: ${error}`);
}
}));
};

init();
Loading

0 comments on commit 0ecc652

Please sign in to comment.