WIP: refactor: port to JS
This should hopefully reduce the complexity of the action
This commit is contained in:
parent
1b14f63169
commit
8925f3da6d
20 changed files with 215060 additions and 109 deletions
|
@ -2,7 +2,7 @@
|
|||
end_of_line = lf
|
||||
charset = utf-8
|
||||
|
||||
[*.{nix,json,sh}]
|
||||
[*.{nix,json,sh,js}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
|
|
@ -8,7 +8,7 @@ jobs:
|
|||
check:
|
||||
- treefmt
|
||||
steps:
|
||||
- uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4
|
||||
- uses: 'https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4
|
||||
- name: Run checks
|
||||
run: |
|
||||
nix --version
|
||||
|
@ -18,11 +18,12 @@ jobs:
|
|||
runs-on: nixos
|
||||
needs: check
|
||||
steps:
|
||||
- uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4
|
||||
- uses: 'https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4
|
||||
- run: nix --version
|
||||
- name: Create Size Report
|
||||
uses: ./
|
||||
with:
|
||||
system: x86_64-linux
|
||||
# Create a comment on the associated PR
|
||||
comment-on-pr: ${{ github.ref_name != 'main' }}
|
||||
# Generate artifacts on main (to speed up comparisons)
|
||||
|
|
|
@ -7,7 +7,7 @@ jobs:
|
|||
check-renovaterc:
|
||||
runs-on: nixos
|
||||
steps:
|
||||
- uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4
|
||||
- uses: 'https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4
|
||||
- name: Validate renovaterc.json
|
||||
run: |
|
||||
nix --version
|
||||
|
|
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
* text=auto eol=lf
|
||||
|
||||
dist/** -diff linguist-generated=true
|
103
.gitignore
vendored
103
.gitignore
vendored
|
@ -1 +1,104 @@
|
|||
result*
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
|
||||
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# OS metadata
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Ignore built ts files
|
||||
__tests__/runner/*
|
||||
|
||||
# IDE files
|
||||
.idea
|
||||
*.code-workspace
|
||||
|
|
5
.prettierignore
Normal file
5
.prettierignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
.DS_Store
|
||||
.licenses/
|
||||
dist/
|
||||
node_modules/
|
||||
coverage/
|
15
.prettierrc.yml
Normal file
15
.prettierrc.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
# See: https://prettier.io/docs/en/configuration
|
||||
printWidth: 80
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
semi: false
|
||||
singleQuote: true
|
||||
quoteProps: as-needed
|
||||
jsxSingleQuote: false
|
||||
trailingComma: none
|
||||
bracketSpacing: true
|
||||
bracketSameLine: true
|
||||
arrowParens: always
|
||||
proseWrap: always
|
||||
htmlWhitespaceSensitivity: css
|
||||
endOfLine: lf
|
22
README.md
22
README.md
|
@ -2,9 +2,11 @@
|
|||
|
||||
Use `nix path-info` to query the size of flake outputs and produce a report.
|
||||
|
||||
This repost can be posted to a PR (as formatted markdown) and/or uploaded as a workflow artifact.
|
||||
This repost can be posted to a PR (as formatted markdown) and/or uploaded as a
|
||||
workflow artifact.
|
||||
|
||||
Requires `nix`, `jq`, `curl`, `sed`, `gunzip`, `tar` and `coreutils` to be in the runner's path.
|
||||
Requires `nix`, `jq`, `curl`, `sed`, `gunzip`, `tar` and `coreutils` to be in
|
||||
the runner's path.
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -39,23 +41,29 @@ For more details see the [action.yaml](./action.yml) file.
|
|||
**Definitions:**
|
||||
|
||||
- `Name`: the name of the package/configuration.
|
||||
- `Size`: the closure size (size on disk/NAR size + all transitive dependencies).
|
||||
- `Size`: the closure size (size on disk/NAR size + all transitive
|
||||
dependencies).
|
||||
- `NAR Size`: the size of the build output (package without the dependencies).
|
||||
- `[NAR] Size Change`: the amount changed compared to the main branch.
|
||||
|
||||
**Tips on reading this data:**
|
||||
|
||||
- For NixOS configurations you generally care only about the `Size` (closure size/size on disk).
|
||||
- For NixOS configurations you generally care only about the `Size` (closure
|
||||
size/size on disk).
|
||||
- Reduce the `Size` by disabling unneeded services/default packages.
|
||||
- For Packages you care about both the `Size` and the `NAR Size`.
|
||||
- Reduce the `NAR Size` by reducing the size of the build outputs, e.g. don't copy unnecessary data to the $out dir, optimize binaries for size, etc.
|
||||
- Reduce the `NAR Size` by reducing the size of the build outputs, e.g. don't
|
||||
copy unnecessary data to the $out dir, optimize binaries for size, etc.
|
||||
- Reduce the `Size` by reducing the dependencies (e.g. `buildInputs`).
|
||||
- Don't worry too much about size, some dependencies are deduplicated, e.g. `glibc` adds ~40MiB to the `Size`, but is generally shared by ~every binary on the system, so, chances are, you are already including it from somewhere else and statically linking with e.g. `musl` is not gonna improve things.
|
||||
- Don't worry too much about size, some dependencies are deduplicated, e.g.
|
||||
`glibc` adds ~40MiB to the `Size`, but is generally shared by ~every binary
|
||||
on the system, so, chances are, you are already including it from somewhere
|
||||
else and statically linking with e.g. `musl` is not gonna improve things.
|
||||
|
||||
# NixOS Configurations
|
||||
|
||||
| Name | Size | Size Change | NAR Size | NAR Size Change |
|
||||
|------|-----:|------------:|---------:|----------------:|
|
||||
| -------- | ----: | ----------: | -------: | --------------: |
|
||||
| `gemini` | 11Gi | -2.4Mi | 28Ki | 0 |
|
||||
| `leo` | 1.6Gi | 0 | 25Ki | 0 |
|
||||
| `libra` | 9.4Gi | -2.4Mi | 28Ki | 0 |
|
||||
|
|
96
action.yml
96
action.yml
|
@ -32,6 +32,9 @@ inputs:
|
|||
|
||||
This is a no-op in case no PR is associated with the current branch.
|
||||
default: 'true'
|
||||
system:
|
||||
description: |
|
||||
The nix system name to query the packages of (e.g. x86_64-linux)
|
||||
# Generate workflow artifact
|
||||
generate-artifact:
|
||||
description: Export the generated markdown document as a workflow artifact.
|
||||
|
@ -65,94 +68,5 @@ inputs:
|
|||
default: ${{ github.base_ref }}
|
||||
outputs:
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Find PR (if it exists)
|
||||
id: pr-number
|
||||
if: inputs.comment-on-pr == 'true'
|
||||
run: |
|
||||
. "$GITHUB_ACTION_PATH/scripts/utils.sh"
|
||||
|
||||
log 'Determine head_ref'
|
||||
# For push & tag events it'll bet GITHUB_REF_NAME, for pull_request events it'll be GITHUB_HEAD_REF
|
||||
head_ref=${GITHUB_REF_NAME:-$GITHUB_HEAD_REF}
|
||||
|
||||
log "Get PR number for $head_ref"
|
||||
prs=$(curl -X 'GET' \
|
||||
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls?state=open&sort=recentupdate" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H 'Accept: application/json')
|
||||
|
||||
pr_number=$(echo "$prs" |
|
||||
jq --arg head_ref "$head_ref" '.[] | select(.head.ref == $head_ref) | .number')
|
||||
|
||||
# This seems to create the file???
|
||||
log "GITHUB_OUTPUT=$GITHUB_OUTPUT"
|
||||
log "$(ls -l "$GITHUB_OUTPUT")"
|
||||
|
||||
# Protect against running before a PR is made or if it is triggered on the main branch
|
||||
if [ -z "$pr_number" ]; then
|
||||
warn "No PR created for this commit"
|
||||
echo "pr-number=" >> "$GIHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Retrieved index: $pr_number"
|
||||
log "Expected PR URL: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/pulls/$pr_number"
|
||||
|
||||
echo "pr-number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
- name: Find previous comment (if present)
|
||||
# We want to generate a comment, and we we able to fin the PR number
|
||||
if: inputs.comment-on-pr == 'true' && steps.pr-number.outputs.pr-number != ''
|
||||
id: find-comment
|
||||
uses: https://github.com/peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
|
||||
with:
|
||||
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
direction: first
|
||||
body-includes: "<!-- AUTOGENERATED by nix-flake-outputs-size action -->"
|
||||
- name: Create report
|
||||
if: inputs.comment-on-pr == 'true' || inputs.generate-artifact == 'true'
|
||||
env:
|
||||
PR_ID: ${{ steps.pr-number.outputs.pr-number }}
|
||||
COMMENT: ${{ inputs.comment-on-pr }}
|
||||
COMMENT_ID: ${{ steps.find-comment.outputs.comment-id }}
|
||||
ARTIFACT_NAME: ${{ inputs.artifact-name }}
|
||||
DO_COMPARISON: ${{ inputs.do-comparison }}
|
||||
BASE_BRANCH: ${{ inputs.base-branch }}
|
||||
JOB_NAME: ${{ inputs.job-name }}
|
||||
run: |
|
||||
. "$GITHUB_ACTION_PATH/scripts/utils.sh"
|
||||
|
||||
# Input validation
|
||||
if [ "$DO_COMPARISON" = 'true' ] && [ -z "$JOB_NAME" ]; then
|
||||
error 'job-name should be set if you want to generate a comparison report'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create Size Report
|
||||
"$GITHUB_ACTION_PATH/scripts/create-report.sh" report.json
|
||||
|
||||
# Nothing else to do
|
||||
if [ "$COMMENT" != 'true' ]; then exit 0; fi
|
||||
|
||||
# Try to do a comparison report
|
||||
if [ "$DO_COMPARISON" = 'true' ]; then
|
||||
if "$GITHUB_ACTION_PATH/scripts/retrieve-old-report.sh" && [ -f old-report.json ]; then
|
||||
log "Reporting on sizes and comparing to sizes in $HEAD_BRANCH"
|
||||
|
||||
"$GITHUB_ACTION_PATH/scripts/comment_on_pr.sh" report.json old-report.json
|
||||
exit 0
|
||||
else
|
||||
error 'Failed to do comparison, fallback to posting the report without them'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Just report values
|
||||
log 'Reporting on sizes'
|
||||
"$GITHUB_ACTION_PATH/scripts/comment_on_pr.sh" report.json
|
||||
- name: Upload Artifact
|
||||
uses: https://git.salame.cl/actions/upload-artifact@v4
|
||||
if: inputs.generate-artifact == 'true'
|
||||
with:
|
||||
path: report.json
|
||||
name: ${{ inputs.artifact-name }}
|
||||
using: node20
|
||||
main: dist/index.js
|
||||
|
|
202419
dist/index.js
generated
vendored
Normal file
202419
dist/index.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/index.js.map
generated
vendored
Normal file
1
dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
61
eslint.config.mjs
Normal file
61
eslint.config.mjs
Normal file
|
@ -0,0 +1,61 @@
|
|||
// See: https://eslint.org/docs/latest/use/configure/configuration-files
|
||||
|
||||
import { fixupPluginRules } from '@eslint/compat'
|
||||
import { FlatCompat } from '@eslint/eslintrc'
|
||||
import js from '@eslint/js'
|
||||
import _import from 'eslint-plugin-import'
|
||||
import jest from 'eslint-plugin-jest'
|
||||
import prettier from 'eslint-plugin-prettier'
|
||||
import globals from 'globals'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
})
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ['**/coverage', '**/dist', '**/linter', '**/node_modules']
|
||||
},
|
||||
...compat.extends(
|
||||
'eslint:recommended',
|
||||
'plugin:jest/recommended',
|
||||
'plugin:prettier/recommended'
|
||||
),
|
||||
{
|
||||
plugins: {
|
||||
import: fixupPluginRules(_import),
|
||||
jest,
|
||||
prettier
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.jest,
|
||||
Atomics: 'readonly',
|
||||
SharedArrayBuffer: 'readonly'
|
||||
},
|
||||
|
||||
ecmaVersion: 2023,
|
||||
sourceType: 'module'
|
||||
},
|
||||
|
||||
rules: {
|
||||
camelcase: 'off',
|
||||
'eslint-comments/no-use': 'off',
|
||||
'eslint-comments/no-unused-disable': 'off',
|
||||
'i18n-text/no-en': 'off',
|
||||
'import/no-namespace': 'off',
|
||||
'no-console': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'prettier/prettier': 'error'
|
||||
}
|
||||
}
|
||||
]
|
|
@ -26,10 +26,12 @@
|
|||
# Setup formatters
|
||||
treefmt = {
|
||||
# Ignore images
|
||||
settings.global.excludes = [ "*.png" ];
|
||||
settings.global.excludes = [
|
||||
"*.png"
|
||||
"dist/*"
|
||||
];
|
||||
projectRootFile = "flake.nix";
|
||||
programs = {
|
||||
mdformat.enable = true;
|
||||
nixfmt.enable = true;
|
||||
shfmt.enable = true;
|
||||
shellcheck.enable = true;
|
||||
|
|
30
jest.config.js
Normal file
30
jest.config.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// See: https://jestjs.io/docs/configuration
|
||||
|
||||
/** @type {import('jest').Config} */
|
||||
const jestConfig = {
|
||||
clearMocks: true,
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['./src/**'],
|
||||
coverageDirectory: './coverage',
|
||||
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
|
||||
coverageReporters: ['json-summary', 'text', 'lcov'],
|
||||
// Uncomment the below lines if you would like to enforce a coverage threshold
|
||||
// for your action. This will fail the build if the coverage is below the
|
||||
// specified thresholds.
|
||||
// coverageThreshold: {
|
||||
// global: {
|
||||
// branches: 100,
|
||||
// functions: 100,
|
||||
// lines: 100,
|
||||
// statements: 100
|
||||
// }
|
||||
// },
|
||||
moduleFileExtensions: ['js'],
|
||||
reporters: ['default'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.js'],
|
||||
testPathIgnorePatterns: ['/dist/', '/node_modules/'],
|
||||
verbose: true
|
||||
}
|
||||
|
||||
export default jestConfig
|
12141
package-lock.json
generated
Normal file
12141
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
66
package.json
Normal file
66
package.json
Normal file
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"name": "nix-flake-outputs-size-report",
|
||||
"description": "Use 'nix-path-info' to query the size of outputs and produce a markdown report",
|
||||
"version": "0.1.0",
|
||||
"author": "Jalil David Salamé Messina",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"homepage": "https://git.salame.cl/jalil/nix-flake-outputs-size#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://git.salame.cl/jalil/nix-flake-outputs-size.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://git.salame.cl/jalil/nix-flake-outputs-size/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"actions"
|
||||
],
|
||||
"exports": {
|
||||
".": "./dist/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "npm run format:write && npm run package",
|
||||
"ci-test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest",
|
||||
"coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg",
|
||||
"format:write": "npx prettier --write .",
|
||||
"format:check": "npx prettier --check .",
|
||||
"lint": "npx eslint .",
|
||||
"local-action": "npx @github/local-action . src/main.js .env",
|
||||
"package": "npx rollup --config rollup.config.js",
|
||||
"package:watch": "npm run package -- --watch",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest",
|
||||
"all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^2.3.2",
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^6.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.3.1",
|
||||
"@github/local-action": "^3.2.1",
|
||||
"@jest/globals": "^30.0.4",
|
||||
"@rollup/plugin-commonjs": "^28.0.6",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.0.1",
|
||||
"eslint-plugin-prettier": "^5.5.1",
|
||||
"jest": "^30.0.4",
|
||||
"make-coverage-badge": "^1.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-eslint": "^16.4.2",
|
||||
"rollup": "^4.44.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-x64-gnu": "*"
|
||||
}
|
||||
}
|
11
report.json
Normal file
11
report.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "hello",
|
||||
"size": 33159640,
|
||||
"narSize": 234680
|
||||
}
|
||||
],
|
||||
"nixosConfigurations": [],
|
||||
"homeConfigurations": []
|
||||
}
|
18
rollup.config.js
Normal file
18
rollup.config.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
// See: https://rollupjs.org/introduction/
|
||||
|
||||
import commonjs from '@rollup/plugin-commonjs'
|
||||
import json from '@rollup/plugin-json'
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve'
|
||||
|
||||
const config = {
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
esModule: true,
|
||||
file: 'dist/index.js',
|
||||
format: 'es',
|
||||
sourcemap: true
|
||||
},
|
||||
plugins: [commonjs(), json(), nodeResolve({ preferBuiltins: true })]
|
||||
}
|
||||
|
||||
export default config
|
8
src/index.js
Normal file
8
src/index.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* The entrypoint for the action. This file simply imports and runs the action's
|
||||
* main logic.
|
||||
*/
|
||||
import { run } from './main.js'
|
||||
|
||||
/* istanbul ignore next */
|
||||
run()
|
145
src/main.js
Normal file
145
src/main.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as github from '@actions/github'
|
||||
import { DefaultArtifactClient } from '@actions/artifact'
|
||||
import * as fs from 'node:fs/promises'
|
||||
|
||||
/**
|
||||
* The main function for the action.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the action is complete.
|
||||
*/
|
||||
export async function run() {
|
||||
try {
|
||||
const comment = core.getBooleanInput('comment-on-pr', { required: false })
|
||||
const upload = core.getBooleanInput('generate-artifact', {
|
||||
required: false
|
||||
})
|
||||
const artifactName = core.getInput('artifact-name', { required: false })
|
||||
const compare = core.getBooleanInput('do-comparison', { required: false })
|
||||
const jobName = core.getInput('job-name', { required: false })
|
||||
const baseBranch = core.getInput('base-branch', { required: false })
|
||||
const system = core.getInput('system', { required: true })
|
||||
|
||||
if (!comment && !upload) {
|
||||
core.error(
|
||||
'Both comment-on-pr and generate-artifact were set to false, nothing to do, consider disabling the action instead'
|
||||
)
|
||||
core.setFailed('Neither commenting nor uploading a report ... why?')
|
||||
return
|
||||
}
|
||||
|
||||
const flakeInfo = JSON.parse(
|
||||
await collectOutput('nix', ['flake', 'show', '--json'])
|
||||
)
|
||||
core.debug(`nix flake show --json: ${flakeInfo}`)
|
||||
|
||||
const report = await core.group('Generating size report', () =>
|
||||
generateReport(flakeInfo, system)
|
||||
)
|
||||
|
||||
if (upload) {
|
||||
const artifact = new DefaultArtifactClient()
|
||||
await fs.writeFile(artifactName, JSON.stringify(report))
|
||||
const { id, size } = artifact.uploadArtifact(artifactName, [artifactName])
|
||||
|
||||
core.info(`Uploaded report ${artifactName} (${size}B) with id ${id}`)
|
||||
}
|
||||
|
||||
// Done
|
||||
if (!comment) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: compare reports and create comment
|
||||
} catch (error) {
|
||||
// Fail the workflow run if an error occurs
|
||||
if (error instanceof Error) core.setFailed(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
async function generateReport(flakeInfo, system) {
|
||||
const packages = getPackages(flakeInfo, system)
|
||||
const hmConfigs = getKeys(flakeInfo, 'homeConfigurations')
|
||||
const nixosConfigs = getKeys(flakeInfo, 'nixosConfigurations')
|
||||
|
||||
core.info(`packages: ${packages}`)
|
||||
core.info(`homeConfigurations: ${hmConfigs}`)
|
||||
core.info(`nixosConfigurations: ${nixosConfigs}`)
|
||||
|
||||
const pkgSizes = await core.group('Calculating size of packages', () =>
|
||||
calculateSizeOf(packages, (pkg) => `.#${pkg}`)
|
||||
)
|
||||
|
||||
const hmConfigsSizes = await core.group(
|
||||
'Calculating size of Home-Manager Configurations',
|
||||
() =>
|
||||
calculateSizeOf(
|
||||
hmConfigs,
|
||||
(config) => `.#homeConfigurations.${config}.activationPackages`
|
||||
)
|
||||
)
|
||||
|
||||
const nixosConfigsSizes = await core.group(
|
||||
'Calculating size of NixOS Configurations',
|
||||
() =>
|
||||
calculateSizeOf(
|
||||
nixosConfigs,
|
||||
(config) =>
|
||||
`.#nixosConfigurations.${config}.config.system.build.toplevel`
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
packages: pkgSizes,
|
||||
nixosConfigurations: nixosConfigsSizes,
|
||||
homeConfigurations: hmConfigsSizes
|
||||
}
|
||||
}
|
||||
|
||||
async function calculateSizeOf(names, nameToInstallable) {
|
||||
let sizes = []
|
||||
for (const name of names) {
|
||||
sizes.push(await calculateSize(nameToInstallable(name)))
|
||||
}
|
||||
return sizes
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the packages from a `nix flake show --json` blob
|
||||
*
|
||||
* @returns {Array<String>} the packages in the current flake for the specific system
|
||||
*/
|
||||
function getPackages(flakeInfo, system) {
|
||||
return 'packages' in flakeInfo ? getKeys(flakeInfo.packages, system) : []
|
||||
}
|
||||
|
||||
function getKeys(flakeInfo, key) {
|
||||
return key in flakeInfo ? Object.keys(flakeInfo[key]) : []
|
||||
}
|
||||
|
||||
async function calculateSize(installable) {
|
||||
const path = await collectOutput('nix', [
|
||||
'build',
|
||||
'--print-out-paths',
|
||||
installable
|
||||
])
|
||||
const data = JSON.parse(
|
||||
await collectOutput('nix', ['path-info', '--closure-size', '--json', path])
|
||||
)
|
||||
data.path = path
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
async function collectOutput(cmd, args) {
|
||||
let output = ''
|
||||
await exec.exec(cmd, args, {
|
||||
listeners: {
|
||||
stdout: (data) => {
|
||||
output += data.toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
return output.trim()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue