Skip to content
Merged
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ jobs:
uses: ./
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
pattern: index.js
pattern: index.js
install-script: npm ci
build-script: npm run build
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

A GitHub action that reports changes in compressed file sizes on your PRs.

- Automatically uses `yarn`, `pnpm`, `bun`, or `npm ci` when lockfiles are present
- Builds your PR, then builds the target and compares between the two
- Doesn't upload anything or rely on centralized storage
- Supports [custom build scripts](#customizing-the-build) and [file patterns](#customizing-the-list-of-files)
Expand All @@ -27,8 +26,15 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: preactjs/compressed-size-action@v2
with:
install-script: npm ci
build-script: npm run build
clean-script: npm run clean
```

> [!IMPORTANT]
> When using custom `build-script`, `install-script`, or `clean-script` options, ensure that the specified scripts exist in both the current branch (PR) and the base branch (target). The action will fail if a script is missing from either branch.

Comment thread
unrevised6419 marked this conversation as resolved.
### Customizing the Installation

By default, `compressed-size-action` will install dependencies according to which lockfiles are present, if any. However, if you need to run a different installation command, you can pass a custom script to do so. For example, to use `npm ci` with the `--workspace` option:
Expand Down Expand Up @@ -82,7 +88,7 @@ jobs:
- uses: actions/checkout@v2
- uses: preactjs/compressed-size-action@v2
with:
+ build-script: "ci"
+ build-script: "npm run build"
```

#### Clean up state between builds
Expand All @@ -100,7 +106,7 @@ jobs:
- uses: preactjs/compressed-size-action@v2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ clean-script: "clean"
+ clean-script: "npm run clean"
```

```jsonc
Expand Down
7 changes: 3 additions & 4 deletions action.yml
Comment thread
unrevised6419 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ inputs:
required: false
default: ${{ github.token }}
clean-script:
description: 'An npm-script that cleans/resets state between branch builds'
description: 'A script that cleans/resets state between branch builds'
install-script:
required: false
Comment thread
rschristian marked this conversation as resolved.
description: 'Custom installation script to run to set up the dependencies in your project'
build-script:
description: 'The npm-script to run that builds your project'
default: 'build'
required: true
description: 'The script to run that builds your project'
compression:
description: 'The compression algorithm to use: "gzip" or "brotli"'
show-total:
Expand Down
49 changes: 23 additions & 26 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getInput, setFailed, startGroup, endGroup, debug } from '@actions/core'
import { context, getOctokit } from '@actions/github';
import { exec } from '@actions/exec';
import SizePlugin from 'size-plugin-core';
import { getPackageManagerAndInstallScript, diffTable, toBool, stripHash, getSortOrder } from './utils.js';
import { diffTable, toBool, stripHash, getSortOrder } from './utils.js';

/**
* @typedef {ReturnType<typeof import("@actions/github").getOctokit>} Octokit
Expand Down Expand Up @@ -46,22 +46,21 @@ async function run(octokit, context, token) {
stripHash: stripHash(getInput('strip-hash'))
});

const buildScript = getInput('build-script') || 'build';
const buildScript = getInput('build-script', { required: true });
Comment thread
rschristian marked this conversation as resolved.
const cwd = process.cwd();

let { packageManager, installScript } = await getPackageManagerAndInstallScript(cwd);
if (getInput('install-script')) {
installScript = getInput('install-script');
}
const installScript = getInput('install-script');

startGroup(`[current] Install Dependencies`);
console.log(`Installing using ${installScript}`);
Comment thread
rschristian marked this conversation as resolved.
await exec(installScript);
endGroup();
if (installScript) {
startGroup(`[current] Install Dependencies`);
console.log(`Running install script: "${installScript}"`);
await exec(installScript);
endGroup();
}

startGroup(`[current] Build using ${packageManager}`);
console.log(`Building using ${packageManager} run ${buildScript}`);
Comment thread
rschristian marked this conversation as resolved.
await exec(`${packageManager} run ${buildScript}`);
startGroup(`[current] Building`);
console.log(`Running build script: "${buildScript}"`);
await exec(buildScript);
endGroup();

// In case the build step alters a JSON-file, ....
Expand Down Expand Up @@ -100,24 +99,22 @@ async function run(octokit, context, token) {

const cleanScript = getInput('clean-script');
if (cleanScript) {
startGroup(`[base] Cleanup via ${packageManager} run ${cleanScript}`);
await exec(`${packageManager} run ${cleanScript}`);
startGroup(`[base] Cleanup`);
console.log(`Running clean script: "${cleanScript}"`);
await exec(cleanScript);
endGroup();
}

startGroup(`[base] Install Dependencies`);

({ packageManager, installScript } = await getPackageManagerAndInstallScript(cwd));
if (getInput('install-script')) {
installScript = getInput('install-script');
if (installScript) {
startGroup(`[base] Install Dependencies`);
console.log(`Running install script: "${installScript}"`);
await exec(installScript);
endGroup();
}

console.log(`Installing using ${installScript}`);
await exec(installScript);
endGroup();

startGroup(`[base] Build using ${packageManager}`);
await exec(`${packageManager} run ${buildScript}`);
startGroup(`[base] Building`);
console.log(`Running build script: "${buildScript}"`);
await exec(buildScript);
endGroup();

// In case the build step alters a JSON-file, ....
Expand Down
32 changes: 0 additions & 32 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,6 @@
import fs from 'fs';
import path from 'path';
import prettyBytes from 'pretty-bytes';

/**
* @param {string} cwd
* @returns {Promise<{ packageManager: string, installScript: string }>}
*/
export async function getPackageManagerAndInstallScript(cwd) {
const [yarnLockExists, pnpmLockExists, bunLockBinaryExists, bunLockExists, packageLockExists] = await Promise.all([
fileExists(path.resolve(cwd, 'yarn.lock')),
fileExists(path.resolve(cwd, 'pnpm-lock.yaml')),
fileExists(path.resolve(cwd, 'bun.lockb')),
fileExists(path.resolve(cwd, 'bun.lock')),
fileExists(path.resolve(cwd, 'package-lock.json')),
]);

let packageManager = 'npm';
let installScript = 'npm install';
if (yarnLockExists) {
installScript = 'yarn --frozen-lockfile';
packageManager = 'yarn';
} else if (pnpmLockExists) {
installScript = 'pnpm install --frozen-lockfile';
packageManager = 'pnpm';
} else if (bunLockBinaryExists || bunLockExists) {
installScript = 'bun install --frozen-lockfile';
packageManager = 'bun';
} else if (packageLockExists) {
installScript = 'npm ci';
}

return { packageManager, installScript };
}

/**
* Check if a given file exists and can be accessed.
* @param {string} filename
Expand Down
14 changes: 1 addition & 13 deletions tests/utils.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path';
import { toBool, getDeltaText, iconForDifference, diffTable, getPackageManagerAndInstallScript, fileExists, stripHash } from '../src/utils.js';
import { toBool, getDeltaText, iconForDifference, diffTable, fileExists, stripHash } from '../src/utils.js';

test('toBool', () => {
expect(toBool('1')).toBe(true);
Expand Down Expand Up @@ -76,18 +76,6 @@ test('diffTable', () => {
expect(diffTable(files, { ...defaultOptions, sortBy: 'Change:desc' })).toMatchSnapshot();
});

test('getPackageManagerAndInstallScript', async () => {
let cwd = process.cwd();
let { packageManager, installScript } = await getPackageManagerAndInstallScript(cwd);
expect(packageManager).toBe('npm');
expect(installScript).toBe('npm ci');

cwd = path.join(cwd, 'tests');
({ packageManager, installScript } = await getPackageManagerAndInstallScript(cwd));
expect(packageManager).toBe('npm');
expect(installScript).toBe('npm install');
});

test('fileExists', async () => {
expect(await fileExists('package.json')).toBe(true);
expect(await fileExists('file-that-does-not-exist')).toBe(false);
Expand Down