Compare commits

...

240 Commits
v5 ... v21

Author SHA1 Message Date
Graham Christensen c5a866b6ab Update to determinate by default (#208)
* Update to determinate by default

Implements https://github.com/DeterminateSystems/nix-src/issues/201

* Fixup the version verification script
2025-11-10 09:48:50 -05:00
Graham Christensen 89b1f59ae9 Drop x86_64-darwin (#207)
* Drop x86_64-darwin

Implements https://github.com/DeterminateSystems/nix-src/issues/224

* Force back to v3.12.2 for users who don't otherwise specify a tag

* ci: don't try to render the devshell on intel macOS

* Try an error?

* Update messaging to be more action-oriented
2025-11-09 22:55:22 -05:00
Luc Perkins 86a5f59de1 Merge pull request #206 from detsys-pr-bot/detsys-ts-update-cb28f5861548d8a85d054c4d6e8e0cd3d3c94329
Update `detsys-ts`: Merge pull request #114 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-47c548f420
2025-11-07 13:02:42 -03:00
lucperkins 64a1e1d1cb Update detsys-ts for: Merge pull request #114 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-47c548f420 (cb28f5861548d8a85d054c4d6e8e0cd3d3c94329) 2025-11-07 15:52:50 +00:00
Graham Christensen 2fd3724578 If determinate is false, pass --prefer-upstream (#202)
* If determinate is false, pass --prefer-upstream

* Regenerate

* Update to an installer version that supports preferring upstream

* Delete the rev test, since rev uploads appoar to have broken a long time ago

* Fixup: expect upstream nix at the moment
2025-10-24 22:24:28 -04:00
Luc Perkins 45a18a6995 Merge pull request #203 from detsys-pr-bot/detsys-ts-update-285768c0d657f9709cb689893f12895c36923093
Update `detsys-ts`: Merge pull request #109 from DeterminateSystems/tsup-to-tsdown
2025-09-12 14:50:59 +02:00
lucperkins d3ddf0223c Update detsys-ts for: Merge pull request #109 from DeterminateSystems/tsup-to-tsdown (285768c0d657f9709cb689893f12895c36923093) 2025-09-12 12:39:38 +00:00
gustavderdrache 786fff0690 Apply fixups from CodeRabbit review (#200) 2025-09-09 10:54:24 -04:00
gustavderdrache f161ab07ed Treat FlakeHub logins as a funnel (#199) 2025-09-09 10:40:05 -04:00
gustavderdrache 61ce7897f4 Merge pull request #198 from DeterminateSystems/gustavderdrache/push-mzwwpswkrrup
Record events if authentication is skipped
2025-09-09 09:58:05 -04:00
gustavderdrache 44f3801e21 Improve messages for when auth isn't available 2025-09-09 09:48:10 -04:00
gustavderdrache cb6d4e86fa Standardize login failure events 2025-09-09 09:44:32 -04:00
gustavderdrache e686131f84 Record events if authentication is skipped 2025-09-08 16:04:19 -04:00
Graham Christensen 2c3a2981f1 Report the number of nix builds that passed / failed (#196)
* Report the number of nix builds that passed / failed

* Upgrade
2025-09-03 12:03:09 -04:00
detsys-pr-bot 18b667a294 Update detsys-ts for: Capture the version of Nix in addition to the nix store version (#108) (c7303495f43d348cac78091ef434443b1ef22485) (#197)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-09-03 15:37:20 +00:00
detsys-pr-bot 428f3c64a3 Update detsys-ts for: Merge pull request #106 from DeterminateSystems/fix-dependabot-warning (6d3f1c5a5781e58b3cd8060cfb578c0c95eeb51e) (#194)
Co-authored-by: lucperkins <1523104+lucperkins@users.noreply.github.com>
2025-07-30 15:59:25 +00:00
detsys-pr-bot 90bb610b90 Update detsys-ts for: Await the request promise so we can cover it with the timout handler (#105) (20c4962e328c1eba8f04da00bbb7a7e307d511e0) (#191)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-07-14 22:53:06 +00:00
detsys-pr-bot c723f3a885 Update detsys-ts for: Skip complicated rewrites, record groups. (#104) (0095c476e55f64d04f1aa1e1bcc2524c329d073a) (#190)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-07-03 09:38:17 -04:00
Luc Perkins 41e0dcf215 Merge pull request #188 from detsys-pr-bot/detsys-ts-update-5084fa8e3263a0bed2383f46e407e6c2936e8289
Update `detsys-ts`: Remove FHC action since it's composite (#103)
2025-06-24 12:56:06 -07:00
grahamc e455bc9d67 Update detsys-ts for: Remove FHC action since it's composite (#103) (5084fa8e3263a0bed2383f46e407e6c2936e8289) 2025-06-23 19:56:57 +00:00
detsys-pr-bot b336b210d0 Update detsys-ts for: Merge pull request #101 from DeterminateSystems/gustavderdrache/write-correlation (e252a66f00e041869f7e402e579141f7b8ab1edf) (#187)
Co-authored-by: gustavderdrache <194893+gustavderdrache@users.noreply.github.com>
2025-06-23 18:40:45 +00:00
Luc Perkins 999d616271 Merge pull request #184 from detsys-pr-bot/detsys-ts-update-4bf247b1cb6b057abe94721ea1bfa131618e2b7f
Update `detsys-ts`: Merge pull request #97 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-a9a1a26a5c
2025-06-02 11:59:04 -07:00
lucperkins 2a6922c6a5 Update detsys-ts for: Merge pull request #97 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-a9a1a26a5c (4bf247b1cb6b057abe94721ea1bfa131618e2b7f) 2025-06-02 18:51:49 +00:00
Luc Perkins 4a562136e6 Merge pull request #182 from DeterminateSystems/graham/fh-813-create-a-determinate-nix-action-with-pinned-releases
Add a note about pinning
2025-05-16 15:46:58 -04:00
Luc Perkins b89da14ed6 Remove unnecessary future tense 2025-05-16 15:38:25 -04:00
Luc Perkins a0000cd639 Remove redundant word 2025-05-16 15:38:09 -04:00
Luc Perkins 9793b3bc29 Fix capitalization 2025-05-16 15:37:31 -04:00
Luc Perkins 3489e2d8c3 Fix verb conjugation 2025-05-16 15:37:23 -04:00
Graham Christensen e4760a7aa0 Add a note about pinning 2025-05-16 15:28:31 -04:00
detsys-pr-bot 2f3746ebff Update detsys-ts for: Merge pull request #95 from DeterminateSystems/graham/fh-813-create-a-determinate-nix-action-with-pinned-releases (74999c82de35e73feb13af2c0e0c3ebb92a17c66) (#181)
Co-authored-by: lucperkins <1523104+lucperkins@users.noreply.github.com>
2025-05-15 21:20:56 +00:00
Graham Christensen 780ad73c03 Ditch the docker shim in favor of direct execution (#180)
Co-authored-by: gustavderdrache <alex.ford@determinate.systems>
2025-05-13 17:34:37 -04:00
Luc Perkins affd83b251 Merge pull request #178 from detsys-pr-bot/detsys-ts-update-e0a5f196fd4e17f2ba1d6ad03300fe532717f7e8
Update `detsys-ts`: Merge pull request #94 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-dde80b0a8d
2025-05-12 07:19:06 -03:00
lucperkins 7e20c99dbd Update detsys-ts for: Merge pull request #94 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-dde80b0a8d (e0a5f196fd4e17f2ba1d6ad03300fe532717f7e8) 2025-05-12 10:12:01 +00:00
Graham Christensen 88762f81a9 Fix an obscure error case where if the only log fails, the rendering is wack (#177)
* Omit extraneous "m"s

* Fix an obscure error case where if the only log fails, the rendering is wack

* Collapse seconds on the  mermaid diagram into MmSs

* Add missing possessive

* Fixup tests, rename collapseSeconds to formatDuration

---------

Co-authored-by: Luc Perkins <lucperkins@gmail.com>
2025-05-08 12:56:31 -04:00
Luc Perkins 7b9fe29d91 Merge pull request #176 from detsys-pr-bot/detsys-ts-update-87c69ec3d48cb353229e74cc2ba8abdef2eb2590f
Update `detsys-ts`: Merge pull request #93 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-a403fbca50
2025-05-04 21:47:10 -03:00
lucperkins 4795fa54eb Update detsys-ts for: Merge pull request #93 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-a403fbca50 (87c69ec3d48cb353229e74cc2ba8abdef2eb2590) 2025-05-05 00:38:20 +00:00
Luc Perkins bec3e50af8 Merge pull request #174 from detsys-pr-bot/detsys-ts-update-19c948d15e766687225515331fbebc216a14ed06
Update `detsys-ts`: Merge pull request #92 from DeterminateSystems/dependabot/npm_and_yarn/npm_and_yarn-de653eece3
2025-04-30 15:49:45 -03:00
lucperkins 138c4e748c Update detsys-ts for: Merge pull request #92 from DeterminateSystems/dependabot/npm_and_yarn/npm_and_yarn-de653eece3 (19c948d15e766687225515331fbebc216a14ed06) 2025-04-30 18:42:20 +00:00
gustavderdrache 7b2eab0f02 Merge pull request #173 from DeterminateSystems/hash-mismatch-summary
Add hash mismatches to summary
2025-04-24 17:33:34 -04:00
Luc Perkins 7ee09f94c3 Provide a link to our guide rather than a URL 2025-04-24 18:26:43 -03:00
gustavderdrache dfa057fae0 s/INFO/TIP/ 2025-04-24 17:12:37 -04:00
gustavderdrache a79af99b14 Add hash mismatches to summary 2025-04-24 16:47:04 -04:00
gustavderdrache 65f0526420 Merge pull request #172 from DeterminateSystems/test-penance
Test penance
2025-04-24 14:44:24 -04:00
gustavderdrache b00ad13101 Clean up unneeded brackets 2025-04-24 14:36:34 -04:00
gustavderdrache 5f843f60e2 Add test for empty build summary case 2025-04-24 14:35:39 -04:00
Luc Perkins 01d7370b1d Merge pull request #171 from DeterminateSystems/suppress-empty-summaries
Correctly suppress empty summaries
2025-04-24 15:30:04 -03:00
gustavderdrache 7c49e2a674 Correctly suppress empty summaries 2025-04-24 14:19:48 -04:00
Graham Christensen 21a544727d Sometimes, two heads are NOT as good as one. (#170) 2025-04-23 19:45:24 -04:00
gustavderdrache b669a07c99 Merge pull request #141 from JTKBowers/main
Check whether the current user has access to KVM before attempting to add udev rule
2025-04-23 18:18:46 -04:00
gustavderdrache 520fb5ebbe Merge remote-tracking branch 'upstream/main' 2025-04-23 18:04:43 -04:00
gustavderdrache 47a222377c Merge pull request #139 from dpc/dpc/jj-vqymqvyntouw
chore: detect existing `nix` installations
2025-04-23 17:59:45 -04:00
gustavderdrache c6e05d595d Merge remote-tracking branch 'upstream/main' into dpc/jj-vqymqvyntouw 2025-04-23 17:51:06 -04:00
gustavderdrache c56aa5176f Regenerate bundle 2025-04-23 17:50:58 -04:00
gustavderdrache ed5212da54 Apply suggestions from code review 2025-04-23 17:43:48 -04:00
gustavderdrache d614ddf8ca Merge pull request #169 from DeterminateSystems/flakehub-login-diagnostics
Show diagnostics for FlakeHub login issues
2025-04-23 17:41:44 -04:00
gustavderdrache e1cdf1927d Show diagnostics for FlakeHub login issues 2025-04-23 17:25:59 -04:00
Graham Christensen aacc1657a2 Don't blow the limits of summaries, by not printing logs if it blows the limit (#168)
* Don't blow the limits of summaries, by not printing logs if it blows the limit

* Print out log summaries for unrendered logs at the END of the console log, so they're easier to find

* fixup

* Pull the default max summary length out
2025-04-23 20:05:44 +00:00
Graham Christensen ce0da527df Summarize the build timeline (#165)
* Show build failure summary

* Record the start timestamp after the selftest

* Cleanup: use default parameter

* Cleanup: don't reassign arguments

* Cleanup: simplify do-while logic

* Cleanup: extract truncation helper

* Cleanup: use locals

* cleanup: minor nits

* fix lints

* build

* Use determinate-nixd's --since flag

* Re-render...

* Fixup the note about 50k being the max

---------

Co-authored-by: gustavderdrache <alex.ford@determinate.systems>
2025-04-16 13:25:51 -07:00
gustavderdrache 902d820b25 Annotate hash mismatches when Determinate features are enabled (#158)
* Render hash mismatches as feedback
* Remove superfluous punctuation
* Use determinate-nixd's hash fix feature
* Feature gate annotations
* Add annotation telemetry
* Remove .drv when rendering pretty derivation names
2025-04-14 12:40:23 -04:00
Luc Perkins 17a3ce76e0 Merge pull request #164 from detsys-pr-bot/detsys-ts-update-f42f6003b4044fede4681778f76342e523671e8f
Update `detsys-ts`: Merge pull request #89 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-0b8d2803d6
2025-04-13 23:46:29 -03:00
lucperkins 52cdd33747 Update detsys-ts for: Merge pull request #89 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-0b8d2803d6 (f42f6003b4044fede4681778f76342e523671e8f) 2025-04-14 02:30:08 +00:00
Luc Perkins 0d28deea2b Merge pull request #162 from detsys-pr-bot/detsys-ts-update-e31aa55518cae49b58723c152c6d0e46ee223ec1
Update `detsys-ts`: Merge pull request #87 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-2f3c1638ee
2025-04-06 22:43:26 -03:00
lucperkins 956acc53ac Update detsys-ts for: Merge pull request #87 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-2f3c1638ee (e31aa55518cae49b58723c152c6d0e46ee223ec1) 2025-04-07 01:17:10 +00:00
detsys-pr-bot 741b61d2a0 Update detsys-ts for: Merge pull request #86 from DeterminateSystems/dependabot/npm_and_yarn/npm_and_yarn-2bd33993d4 (dc7c6d9c7a5d2db79ddc6eccf57d5fc09a391347) (#161)
Co-authored-by: lucperkins <1523104+lucperkins@users.noreply.github.com>
2025-04-04 16:26:22 +00:00
detsys-pr-bot 7239c695c3 Update detsys-ts for: Bump vite from 6.2.3 to 6.2.4 in the npm_and_yarn group (#85) (79634332de50a2cde17cf8d6fe41258af3d4bedf) (#160)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-03-31 19:48:26 +00:00
detsys-pr-bot 28aa4ed62f Update detsys-ts for: Merge pull request #84 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-73588cc3c5 (3ef4baee587df9fe98f70036386e361fa0d6dc7e) (#159)
Co-authored-by: lucperkins <1523104+lucperkins@users.noreply.github.com>
2025-03-31 09:05:09 -04:00
detsys-pr-bot 78d714f6f7 Update detsys-ts: Ignore hyphen-sep'd diags (#83) (#155)
* Update `detsys-ts` for: `Ignore hyphen-sep'd diags (#83)` (`07c7fc924119a8d9879c1c164ae593049d47f648`)

* Wait for the socket to appear

* ...

---------

Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
Co-authored-by: Graham Christensen <graham@grahamc.com>
2025-03-28 15:20:00 -04:00
Graham Christensen 3e92d74f28 fail-fast: false (#156) 2025-03-28 14:17:41 -04:00
detsys-pr-bot 84f3b6ba94 Update detsys-ts for: Merge pull request #82 from DeterminateSystems/even-more-crashes (03533d37dcd46f34d9e99385e665615b221a30d9) (#154)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-03-28 14:19:02 +00:00
detsys-pr-bot 8f9243d6dd Update detsys-ts for: Merge pull request #81 from DeterminateSystems/dont-capture-some-crashes (8d9725c4856301321cd2508f5b8725cfb99366e2) (#153)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-03-27 16:04:36 +00:00
Luc Perkins 480fcd11bd Merge pull request #152 from detsys-pr-bot/detsys-ts-update-38df301720b69972f084538dd44c181269f264b0
Update `detsys-ts`: Merge pull request #80 from DeterminateSystems/fixup-traces
2025-03-27 11:10:33 -03:00
grahamc 2551261839 Update detsys-ts for: Merge pull request #80 from DeterminateSystems/fixup-traces (38df301720b69972f084538dd44c181269f264b0) 2025-03-27 13:47:59 +00:00
Luc Perkins 7f1ff2b54f Merge pull request #151 from detsys-pr-bot/detsys-ts-update-cf33e9577ca7571bf9ebbfe298b4e3e457a58813
Update `detsys-ts`: Merge pull request #79 from DeterminateSystems/dependabot/npm_and_yarn/npm_and_yarn-14f44f5325
2025-03-26 10:00:20 -03:00
lucperkins 1e22780707 Update detsys-ts for: Merge pull request #79 from DeterminateSystems/dependabot/npm_and_yarn/npm_and_yarn-14f44f5325 (cf33e9577ca7571bf9ebbfe298b4e3e457a58813) 2025-03-26 12:32:03 +00:00
Luc Perkins dc965b7805 Merge pull request #150 from DeterminateSystems/update-deps 2025-03-25 19:27:38 -03:00
Cole Helbling fe228f6faf Update @actions/github to 6.0.0 2025-03-25 14:41:42 -07:00
Luc Perkins 300844e532 Merge pull request #149 from DeterminateSystems/flakehub-cache-action 2025-03-24 15:51:30 -03:00
Luc Perkins 86febfe320 Switch to flakehub-cache-action 2025-03-24 00:49:28 -03:00
Luc Perkins 0c7c6d4acd Merge pull request #148 from detsys-pr-bot/detsys-ts-update-9d2b0e4636787bba8b886ddc720f007850e541fb
Update `detsys-ts`: Merge pull request #78 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-0af3b8ec11
2025-03-24 00:45:22 -03:00
lucperkins fbb684a4bf Update detsys-ts for: Merge pull request #78 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-0af3b8ec11 (9d2b0e4636787bba8b886ddc720f007850e541fb) 2025-03-24 01:42:22 +00:00
detsys-pr-bot 37dc9ba6c4 Update detsys-ts for: Merge pull request #74 from DeterminateSystems/dependabot/npm_and_yarn/npm-deps-eb3d92718e (4c7ff9706e6466d7c03c58a3479ed212d6ffb5ba) (#146)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-03-19 17:30:45 -04:00
Jamie Bowers 5e80a7bd8b Check whether the current user already has access to KVM before attempting to add a udev rule. 2025-02-20 11:09:13 +00:00
Dawid Ciężarkiewicz 2d9ffd87e4 chore: add a note about how to install everything
JS has a new shiny tool every 6 months, and I'm not a JS dev, so
it's not immediately obvious why `npm run all` doesn't work, despite
being in a dev shell.
2025-02-07 15:21:18 -08:00
Dawid Ciężarkiewicz 4b27401a78 chore: detect existing nix installations 2025-02-07 15:19:55 -08:00
detsys-pr-bot a48face581 Update detsys-ts for: Merge pull request #71 from DeterminateSystems/updates (b3319a2c78c46d5ad6bc00d3453266d3d9fdde44) (#138)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2025-02-06 16:54:30 +00:00
detsys-pr-bot dea7810afd Update detsys-ts for: Merge pull request #69 from DeterminateSystems/update-deps (eb87094f35072ac911526ad052c3437c9e0c42d6) (#131)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2024-11-26 11:32:08 -05:00
Graham Christensen e50d5f73bf Log in to flakehub on existing installs (#129)
* Log in to flakehub if the machine is already installed

* Put the nix store paths first (in the PATH)

* set the path earlier

* Warn on login failures
2024-11-14 11:41:23 -05:00
detsys-pr-bot 25431d2798 Update detsys-ts for: Merge pull request #67 from DeterminateSystems/allow-obliterating-id-token-privs (4280bc94c9545f31ccf08001cc16f20ccb91b770) (#128)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2024-11-06 14:54:15 -05:00
Graham Christensen b92f66560d Add the job-status option (#125) 2024-10-03 11:40:44 -04:00
Graham Christensen ddfca32d6f Convert flakehub: true to determinate: true (#123)
* Drop the flakehub param to deprecated, use determinate, and log in to flakehub
* Expand the test suite to cover determinate on all our targets

---------

Co-authored-by: Luc Perkins <lucperkins@gmail.com>
2024-09-13 12:36:49 -07:00
detsys-pr-bot da36cb69b1 Update detsys-ts for: Merge pull request #63 from DeterminateSystems/retry-streams (65dd73c562ac60a068340f8e0c040bdcf2c59afe) (#120)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2024-09-04 14:14:02 -04:00
detsys-pr-bot 1406b8b52c Update detsys-ts for: Merge pull request #62 from DeterminateSystems/dont-pull-microstackshots (817e4d4123b6fb4eae5aa557658f25f8539e7240) (#118)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2024-08-26 11:49:32 -04:00
detsys-pr-bot 197bf2b2a5 Update detsys-ts for: Merge pull request #61 from DeterminateSystems/use-coalesce-for-array (e8f6e8f54d85aa0fd3d0b694dd3279a21497a33b) (#117)
Co-authored-by: grahamc <76716+grahamc@users.noreply.github.com>
2024-08-26 14:12:21 +00:00
detsys-pr-bot 452d9c7008 Update detsys-ts for: Merge pull request #58 from DeterminateSystems/collect-crash-logs (cf1897a891edc164a8240f469cd56d14364e6be1) (#116)
Co-authored-by: grahamc <grahamc@users.noreply.github.com>
2024-08-26 13:40:25 +00:00
Graham Christensen 033f039e5c fixup extra arguments (#113) 2024-08-09 14:25:49 -04:00
detsys-pr-bot 468e81bb99 Update detsys-ts for: Merge pull request #57 from DeterminateSystems/fix-typo (17bd89132b0366c45ca87ab5d0361b890fa73f4f) (#112)
Co-authored-by: lucperkins <lucperkins@users.noreply.github.com>
2024-08-09 14:06:28 -04:00
Luc Perkins b164ca3241 Merge pull request #111 from detsys-pr-bot/detsys-ts-update-d353465ae6a55761963005617a7780f2bf7e4ec2
Update `detsys-ts`: Log in to flakehub for 'fh' too (#110)
2024-08-01 18:10:21 +02:00
lucperkins 055e848f13 Update detsys-ts for: Log in to flakehub for 'fh' too (#110) (d353465ae6a55761963005617a7780f2bf7e4ec2) 2024-08-01 14:53:15 +00:00
Graham Christensen d41fccdd9e Log in to flakehub for 'fh' too (#110) 2024-07-26 20:53:16 +00:00
Graham Christensen ab6bcb2d5a Share /lib64 into the container (#109)
* Share /lib64 into the container

* Don't attempt to mount host directories that don't exist
2024-07-22 11:40:01 -04:00
Graham Christensen 0d82cb015a README: correct the source-url parameter docs (#108)
* README: correct the source-url parameter docs

* Fixup formatting
2024-07-10 17:44:31 +00:00
Luc Perkins 2a2ecc1e15 Merge pull request #104 from detsys-pr-bot/detsys-ts-update-bc45b6c0a6318ae30192c4bf23a73dc879bdb632
Update `detsys-ts`:
2024-06-05 15:50:58 -07:00
Luc Perkins 9e19e84fa9 Regenerate dist 2024-06-05 15:45:08 -07:00
detsys-pr-bot dc8972520c Update detsys-ts for: Merge pull request #103 from detsys-pr-bot/detsys-ts-update-515d00bc192ae4460e2122572ebc24020c58ea95 (856a75af22949b76e23f6e54a1b4d27d8816cea4) (#105)
Co-authored-by: lucperkins <lucperkins@users.noreply.github.com>
2024-06-05 22:06:04 +00:00
Luc Perkins 7ad5c49547 Regenerate dist 2024-06-05 14:57:05 -07:00
Luc Perkins 17a448a97b Merge pull request #103 from detsys-pr-bot/detsys-ts-update-515d00bc192ae4460e2122572ebc24020c58ea95
Update detsys-ts: Merge pull request #51 from DeterminateSystems/add-missing-actions-to-update-matrix

Add missing Actions to update matrix
2024-06-05 14:55:50 -07:00
lucperkins 45cb2f89ca Update detsys-ts for: ` (bc45b6c0a6318ae30192c4bf23a73dc879bdb632`) 2024-06-05 21:32:12 +00:00
lucperkins 47dc48605c Update detsys-ts for: Merge pull request #51 from DeterminateSystems/add-missing-actions-to-update-matrix
Add missing Actions to update matrix (515d00bc192ae4460e2122572ebc24020c58ea95)
2024-06-05 21:06:36 +00:00
Luc Perkins 4b8e190ea5 Update detsys-ts (#102) 2024-06-05 16:18:06 -04:00
Cole Helbling 8c320971f9 Merge pull request #100 from DeterminateSystems/serialize
bump
2024-06-03 14:34:06 -07:00
Graham Christensen 7b943f9a7e update 2024-06-03 17:18:28 -04:00
Graham Christensen 40e4bc1e80 bump 2024-06-03 17:11:35 -04:00
Luc Perkins 9d5faf48ab Merge pull request #99 from DeterminateSystems/science/debug-fly
science: probes to debug fly on GHA
2024-06-03 11:54:06 -07:00
Luc Perkins f92f10828b Use coalescing instead of or 2024-06-03 11:47:38 -07:00
Graham Christensen 1025a55627 track timings 2024-06-03 14:37:04 -04:00
Graham Christensen 5adb94fc48 science: probes to debug fly on GHA 2024-06-03 14:19:40 -04:00
Luc Perkins 7993355175 Merge pull request #98 from DeterminateSystems/update-detsys-ts-status-page
Update detsys-ts (status page changes)
2024-06-03 09:18:33 -07:00
Luc Perkins db2c9be88c Update detsys-ts (status page changes) 2024-06-03 09:11:14 -07:00
Graham Christensen a2473ab552 Srv update (#97)
* Update to srv

* Hi, footgun

* Make sure we don't toString promises, update deps

* Update

* Pass - as the default diagnostic endpoint

* Specify the diagnostic suffix

* Update deps

* SRV update
2024-05-31 12:30:37 -04:00
Cole Helbling f51ebf9a6f Merge pull request #96 from DeterminateSystems/fixup-required-tests
tests: make megajob block on failure
2024-05-30 05:53:28 -07:00
Cole Helbling 676d200580 tests: make megajob block on failure
GitHub Actions considers a "skipped" job successful for the purposes
of required jobs for branch protections. We take advantage of this
by failing if any dependent actions failed, or "skip" if they all
succeeded.
2024-05-29 12:39:53 -07:00
Luc Perkins c6857b9a9d Merge pull request #93 from DeterminateSystems/update-detsys-ts
Update detsys-ts
2024-05-29 16:32:28 -03:00
Luc Perkins e5b417b85f Move comment to better location 2024-05-29 16:26:46 -03:00
Luc Perkins 8ef3f8c93e Fix direction of Boolean check 2024-05-29 16:07:07 -03:00
Luc Perkins ad8814ae5d Fix check for ACT environment 2024-05-29 15:59:19 -03:00
Luc Perkins 9c4e8b237e Provide better if statement 2024-05-29 15:51:33 -03:00
Luc Perkins 23e5c435a9 Update detsys-ts 2024-05-29 15:16:45 -03:00
Luc Perkins c3983e7949 Make strict mode input not required 2024-05-23 12:14:07 -03:00
Luc Perkins 3c042d09d2 Add source-binary to action.yml 2024-05-22 18:35:27 -03:00
Luc Perkins 7b0893fcd8 Regenerate dist 2024-05-22 18:29:40 -03:00
Luc Perkins e4f741cb67 Apply internal strict mode to CI runs 2024-05-22 15:41:57 -03:00
Luc Perkins a56dda90ad Update detsys-ts again 2024-05-22 13:47:58 -03:00
Luc Perkins cd7602a5a8 Add workflow conclusion enum 2024-05-22 13:43:59 -03:00
Luc Perkins f6047128c4 Streamline runner OS logic 2024-05-22 13:40:01 -03:00
Luc Perkins 61795779f3 Add ci-mode to action.yml 2024-05-22 13:24:59 -03:00
Luc Perkins 0b690dedac Update detsys-ts 2024-05-22 13:19:09 -03:00
Graham Christensen 75ffa7fc74 Disable docker under act (#90)
* Rename IN_GITHUB_ACTIONS to IN_ACT

* If the trusted runner user is truthy, setup the runner as a trusted user.

The boolean option is always set.

* Set HAS_SYSTEMD in more cases

* Unquote trust-runner-user in the action.yml

* Don't bother with the docker shim under act

* fmt

* Regenerate

* fixup
2024-05-18 18:46:09 -04:00
Luc Perkins 5c2710f363 Merge pull request #91 from DeterminateSystems/fix-source-uri-description
Provide new test matrix for source-* inputs
2024-05-17 11:21:44 -04:00
Luc Perkins 8cc782962a Add to tests 2024-05-17 11:41:26 -03:00
Luc Perkins c1489fff7b Remove more tests 2024-05-17 11:37:53 -03:00
Luc Perkins 4ed4c86fdc Remove branch test 2024-05-17 11:35:28 -03:00
Luc Perkins ccf4610648 Fix branch version 2024-05-17 11:33:26 -03:00
Luc Perkins f97a8a062c Fix PR version 2024-05-17 11:32:15 -03:00
Luc Perkins 766b8830f1 Provide new test matrix for source-* inputs 2024-05-17 11:28:50 -03:00
Luc Perkins fd6c226bf9 Merge pull request #89 from DeterminateSystems/fix-source-uri-description
Update action.yml description for source-url
2024-05-17 10:22:17 -04:00
Luc Perkins 350241e13f Fix expected version 2024-05-17 11:12:58 -03:00
Luc Perkins 481524661c Fix comparison script 2024-05-17 11:10:24 -03:00
Luc Perkins 164c9d00dc Check expected Nix versions using script 2024-05-17 11:04:45 -03:00
Luc Perkins 74f4d10531 Fix name of workflow 2024-05-16 21:07:06 -03:00
Luc Perkins 86a97d5eb6 Add missing checkout action 2024-05-16 21:05:48 -03:00
Luc Perkins 86e8caa071 Fix path in uses declarations 2024-05-16 21:04:04 -03:00
Luc Perkins 151fdae2fc Add more test cases 2024-05-16 21:02:46 -03:00
Luc Perkins 7fcb842097 Undo matrix logic 2024-05-16 20:53:46 -03:00
Luc Perkins 8d9c69de11 Update expected versions 2024-05-16 20:52:41 -03:00
Luc Perkins 6b0b02c6a2 Fix string interpolation (again) 2024-05-16 20:51:04 -03:00
Luc Perkins 6265732741 Fix string interpolation 2024-05-16 20:50:21 -03:00
Luc Perkins 0e85ec287f Add expected Nix versions 2024-05-16 20:49:32 -03:00
Luc Perkins 5385bea1cb Try with somewhat older versions 2024-05-16 20:42:24 -03:00
Luc Perkins d49867b627 Apply matrix strategy 2024-05-16 20:41:04 -03:00
Luc Perkins e8f36a90cd Fix URL for executable 2024-05-16 20:38:07 -03:00
Luc Perkins 397a5c26a7 Update input description and add test workflow 2024-05-16 20:37:01 -03:00
Luc Perkins 8d4286b90e Merge pull request #87 from DeterminateSystems/fix-docker-invocation
Add CI run for aarch64-darwin
2024-05-15 17:25:33 -04:00
Luc Perkins ca7cf68c63 Add megajob called tests 2024-05-15 18:16:09 -03:00
Luc Perkins 94a9e4375c Rename jobs 2024-05-15 17:56:08 -03:00
Luc Perkins da29cfd994 Merge remote-tracking branch 'origin/main' into fix-docker-invocation 2024-05-15 17:51:53 -03:00
Graham Christensen 1e58ce3980 Revert "Fix ESM build" (#86) 2024-05-15 20:45:00 +00:00
Luc Perkins 83c8f7dfdd Fix formatting 2024-05-15 17:44:11 -03:00
Luc Perkins 37d6eb5161 Add CI run for aarch64-darwin 2024-05-15 17:39:35 -03:00
Luc Perkins 813cf108af Merge pull request #83 from DeterminateSystems/fix-esm-build
Fix ESM build
2024-05-15 16:24:28 -04:00
Luc Perkins 4a8c7256d3 Don't clean dist using tsup 2024-05-15 17:18:32 -03:00
Luc Perkins e4a38c246a Regenerate dist 2024-05-15 17:17:12 -03:00
Luc Perkins 9243e9b760 Fix merge conflicts with main 2024-05-15 17:16:08 -03:00
Graham Christensen 8cdf194da9 Update dependencies (#85)
* Update dependencies

* Update deps again :)
2024-05-09 20:29:18 +00:00
Luc Perkins 74b8a1f4e8 Update dependencies 2024-05-03 11:05:02 -03:00
Luc Perkins 51bc05e2ea Fix method of finding docker shims 2024-05-02 17:19:07 -03:00
Luc Perkins 9ffa76fa74 Fix ESM build 2024-05-02 17:07:51 -03:00
Luc Perkins 10f43c0d32 Merge pull request #82 from DeterminateSystems/tsup-build
Switch to tsup for building
2024-05-02 16:45:35 -03:00
Luc Perkins 337589f84d Switch to tsup for building 2024-05-02 16:35:58 -03:00
Luc Perkins 330a0ca1bc Merge pull request #80 from DeterminateSystems/update-checkout-action
Standardize on v4 of the checkout action
2024-05-02 14:20:56 -03:00
Luc Perkins 2c90bb97d0 Standardize on v4 of the checkout action 2024-05-02 14:10:17 -03:00
Luc Perkins 91b8eb110e Merge pull request #79 from DeterminateSystems/fix-mnc-issue
Fix broken CI
2024-05-02 14:05:28 -03:00
Luc Perkins ff2ea37e97 Remove MNC from workflow 2024-05-02 13:58:19 -03:00
Luc Perkins f957521643 Reinstate the MNC prior to reinstall 2024-05-02 13:54:44 -03:00
Luc Perkins 23ddac323e Remove second reinstall setting 2024-05-02 13:49:26 -03:00
Luc Perkins 3785eaaa9b Fix other instance of uninstall/reinstall 2024-05-02 13:48:27 -03:00
Luc Perkins 6b7860826e Remove reinstall setting 2024-05-02 13:47:23 -03:00
Luc Perkins f69dd1d935 Merge pull request #76 from DeterminateSystems/general-cleanup
General JS cleanup
2024-05-02 13:09:27 -03:00
Luc Perkins ff707a0bf7 Fix merge conflict with main 2024-05-02 13:03:16 -03:00
Cole Helbling 7d2a9c4c9d Merge pull request #77 from DeterminateSystems/flakehub-fallback
Gracefully handle FlakeHub login failure
2024-05-02 07:15:43 -07:00
Luc Perkins 1ebf6caddc Remove unnecessary dependencies 2024-05-02 11:05:47 -03:00
Luc Perkins 7acbc80e00 Add names to CI steps 2024-05-02 10:56:42 -03:00
Luc Perkins 57a6360160 Fix build issue due to detsys-ts update 2024-05-02 10:52:54 -03:00
Luc Perkins a2856cdfd2 Prefer coalescing over or-ing 2024-04-24 11:13:40 -03:00
Luc Perkins b87931b2dd Add camelcase check 2024-04-24 11:09:55 -03:00
Cole Helbling 413ac98332 Gracefully handle FlakeHub login failure 2024-04-23 09:55:39 -07:00
Luc Perkins 86cdba7a6e Switch to git diff --exit-code 2024-04-22 13:17:32 -03:00
Luc Perkins c9a02f1141 Use bracket notation for env vars 2024-04-15 19:42:44 -03:00
Luc Perkins 413fb1beb4 Constify events and facts 2024-04-15 19:34:51 -03:00
Luc Perkins 8f4ca496eb Enforce proper casing 2024-04-15 19:23:29 -03:00
Luc Perkins c89881253c Use detsys-ts functions for inputs 2024-04-15 19:09:42 -03:00
Graham Christensen 5c49fa4feb Update detsys-ts (#75) 2024-04-12 15:31:59 -04:00
Graham Christensen 5d2215c1e1 Rebase on top of detsys-ts for abstracting over install.determinate.systems (#74)
* Rebase on top of detsys-ts for abstracting over install.determinate.systems

* Support the legacy nix-installer-xxx source prefs

* Document source-* opts

* Update deps

* cut duration so it doesn't take forever

* Move the complete step into a finally block

* Test a busted run

* come on ...

* update to the main detsys-ts

* Switch to the delegated execution model

* throw an error to check behavior

* Fixup lint errors

* Drop the forced error
2024-04-11 11:58:56 -04:00
Graham Christensen de22e16c47 DETERMINATE_NIX_KVM fixup, support Magic Nix Cache + FlakeHub Cache on Namespace runners (#72)
* Share /bin with nix for post-build-hooks

* test the magic nix cache

* wtf

* permissions

* Share /home and the network namespace too

* test the devshell

* Don't force-set kvm to 0 ... d'oh!

* dev shell support for aarch64-linux

* ?

* More testing /  debug

* Make it run anyway

* Bind /lib too so /bin/sh works ... sigh

* Disable gha-cache for tesing

* Kill the magic nix cache before reinstalling

* Don't set the extra environment variables extraniously

* Enable gha cache again
2024-03-11 19:53:25 -04:00
Ana Hobden e279ba56d8 Merge pull request #67 from DeterminateSystems/hoverbear/fh-161-after-running-in-act-hosts-nix-daemon-is-unusable
Don't use docker shim if only using a mounted docker.sock instead of docker-in-docker
2024-01-11 07:55:46 -08:00
Ana Hobden f4a0ffe230 Don't use docker shim if only using a mounted docker.sock instead of docker-in-docker 2024-01-10 11:45:04 -08:00
Ana Hobden ffea801f30 Merge pull request #66 from DeterminateSystems/hoverbear/fh-160-action-should-work-under-nektosact-in-the-absence-of-systemd
Handle docker not existing.
2024-01-10 08:36:26 -08:00
Ana Hobden 4126bb83b3 Merge branch 'main' into hoverbear/fh-160-action-should-work-under-nektosact-in-the-absence-of-systemd 2024-01-09 10:38:56 -08:00
Ana Hobden 81ee88fd4a Handle docker not existing 2024-01-09 10:36:54 -08:00
Ana Hobden 0f8fa3d242 Merge pull request #64 from DeterminateSystems/hoverbear/fh-156-installer-action-shouldnt-require-sudo
No longer require sudo
2024-01-09 09:50:39 -08:00
Ana Hobden f576e90e2d Fix logic inversion 2024-01-08 13:29:15 -08:00
Ana Hobden 161c1f6904 Use uid not username 2024-01-08 13:06:51 -08:00
Ana Hobden 0e5b724979 No longer require sudo 2024-01-08 10:50:02 -08:00
Cole Mickens 21affdd5d3 action: post-run-job: try clean daemon container, warn on failure (#61)
* flake: add typescript LSP tool

* action: post-run-job: try clean daemon container, warn on failure
2023-12-19 11:01:56 -05:00
Graham Christensen cd46bde16a Support GitHub Enterprise Server using ARC (#59)
* Test nix-installer-action on Namespace.so

It is special in that it doesn't have systemd, and it'd be great to
support Namespace.so. It is also a good test case for a variety
of self-hosted GHA runner use cases.

* Make correlation more confident

* Borrow docker as a process supervisor on Linux GHA runners without systemd

This change introduces a Docker container shim which spawns the Nix
daemon after bind mounting all the relevant paths into the container.

The image is actually completely empty, other than metadata about what
to run.

This is a cheap and cheerful way to get decent process supervision in
environments that don't bring systemd, but do have docker ... which
is most everywhere in the GHA ecosystem.

* Ignore generated files

* Run on arm64 why not

* Load a pre-built image, don't build

* Check the userInfo.username instead of an env var

* Stop double-printing output to the console

* can't rm and restart

* what

* Clean up the container at the end

* Emit the fetch line in the 'installing nix' section

* tweak output

* delete what
2023-12-04 14:17:47 -05:00
Graham Christensen 84fe9e450f Support GitHub Enterprise Server in the github-token access token. (#58) 2023-12-01 10:23:32 -05:00
Graham Christensen 07b8bcba1b KVM support out of the box, plus a refreshed README (#56)
* support kvm

* Refresh the readme

* Update README.md

Co-authored-by: Ana Hobden <operator@hoverbear.org>

* Update README.md

Co-authored-by: Luc Perkins <lucperkins@gmail.com>

* Update README.md

---------

Co-authored-by: Ana Hobden <operator@hoverbear.org>
Co-authored-by: Luc Perkins <lucperkins@gmail.com>
2023-11-21 19:06:06 +00:00
Ana Hobden 5620eb4af6 Merge pull request #53 from DeterminateSystems/use-github-tool-cache-and-exec
Use Github Actions provided tool cache and exec
2023-11-03 08:31:14 -07:00
Ana Hobden 8b5f066806 Use Github Actions provided tool cache and exec 2023-11-02 10:48:10 -07:00
Hugo Santos 7fa8f59903 Detected whether we're running in a Namespace runner, and if so, set init: none. (#52)
Background: Namespace managed runners run each github job in a container, in a
separate micro-vm managed by Namespace. These VMs and containers do not rely on
systemd, and instead use Namespace's own init/process management.
2023-11-02 15:58:37 +00:00
Ana Hobden 721f94f7df Merge pull request #47 from DeterminateSystems/colemickens/fix-stream-close
fix: end the FileStreamWriter for the installer file
2023-10-24 09:22:10 -07:00
Cole Mickens bb22c86823 retries: autoClose, but open file with O_SYNC 2023-10-24 18:01:08 +02:00
Cole Mickens d46d5b144a retries: switch back to piping with non-web node streams 2023-10-24 17:45:43 +02:00
Cole Mickens 663467bee8 main.ts: installer use filehandle, make sure we fsync it before close 2023-10-24 17:35:04 +02:00
Cole Mickens 4e0fccbf7c eslint/tsconfig: validate no floating Promises, adjust tsconfig 2023-10-24 10:40:08 +02:00
Cole Mickens 806550d223 package-lock.json: include node-fetch removal
I'm guessing this got dropped again as part of having multiple
branches in flight and rebasing. It would be good if CI checked that
`npm install` and `npm run build` resulted in *zero* diffs to validate
that generated/lock files match their source at time of CI.
2023-10-24 10:39:49 +02:00
Ana Hobden a5a150bc8f Merge pull request #48 from DeterminateSystems/add-dist-folder-checkl
Add check for dist folder
2023-10-24 01:25:48 -07:00
Ana Hobden 3177c7dd91 npm options wrong post 2023-10-23 11:57:00 -07:00
Ana Hobden 0e429bedc6 Nosave 2023-10-23 11:54:33 -07:00
Ana Hobden 4420be335b Show more in report 2023-10-23 11:53:07 -07:00
Ana Hobden 1ae92f01c0 Of course npm run all does not install, why would it. 2023-10-23 11:51:50 -07:00
Ana Hobden bbcd1efad1 Add check for dist folder 2023-10-23 11:50:08 -07:00
Ana Hobden ba1bee1704 Merge pull request #46 from colemickens/retries
Retry (w/ back-off) downloading the installer binary
2023-10-19 06:42:24 -07:00
Cole Mickens c906fbe810 regenerate dist after rebasing 2023-10-19 11:45:11 +02:00
Cole Mickens 5c1457fc8d retries: interate on stream handling, remove downcast 2023-10-19 11:44:42 +02:00
Cole Mickens 58853de798 main.ts: use fetch-retry, add retry/backoff to fetching installer 2023-10-19 11:44:41 +02:00
Cole Mickens e0fea1fb58 package.json: replace node-fetch with fetch-retry w/ native node fetch 2023-10-19 11:44:41 +02:00
Ana Hobden df82330768 Merge pull request #44 from colemickens/fixup-nix-url-check
main.ts: fixup logic to ensure only one installer url override is set
2023-10-18 10:24:39 -07:00
Cole Mickens 1cd89e7945 .github: allow trigger ci manually (#45) 2023-10-18 11:14:39 -04:00
Cole Mickens b1240359dd main.ts: fixup logic to ensure only one installer url override is set 2023-10-18 16:31:36 +02:00
Graham Christensen bc7b192574 Update the action to use node20 (#41)
* Update nixpkgs to unstable, and nodejs to latest

* Upgrade the action to use node20
2023-10-12 11:19:09 -04:00
35 changed files with 107158 additions and 21176 deletions
+10
View File
@@ -0,0 +1,10 @@
# https://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
+72 -72
View File
@@ -1,74 +1,74 @@
{
"plugins": [
"@typescript-eslint"
],
"extends": [
"plugin:github/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"i18n-text/no-en": "off",
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "off",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowExpressions": true
}
],
"@typescript-eslint/func-call-spacing": [
"error",
"never"
],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true
"plugins": ["@typescript-eslint"],
"extends": ["plugin:github/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"settings": {
"import/resolver": {
"typescript": {}
}
}
},
"rules": {
"i18n-text/no-en": "off",
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/no-base-to-string": "error",
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "error",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowExpressions": true
}
],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true
}
}
+2
View File
@@ -0,0 +1,2 @@
dist/* linguist-generated=true
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# This script verifies that the version of Nix installed on the runner
# matches the version supplied in the first argument.
EXPECTED_VERSION="${1}"
INSTALLED_NIX_VERSION_OUTPUT=$(nix --version)
INSTALLED_NIX_VERSION=$(echo "${INSTALLED_NIX_VERSION_OUTPUT}" | awk '{print $NF}')
if [ "${INSTALLED_NIX_VERSION}" != "${EXPECTED_VERSION}" ]; then
echo "Nix version ${INSTALLED_NIX_VERSION} didn't match expected version ${EXPECTED_VERSION}"
exit 1
else
echo "Success! Nix version ${INSTALLED_NIX_VERSION} installed as expected"
exit 0
fi
+105 -72
View File
@@ -4,87 +4,84 @@ on:
pull_request:
push:
branches: [main]
workflow_dispatch:
jobs:
run-x86_64-linux:
name: Run x86_64 Linux
tests:
runs-on: ubuntu-22.04
needs:
- check-dist-up-to-date
- install-nix
- install-with-non-default-source-inputs
- install-no-id-token
# NOTE(cole-h): GitHub treats "skipped" as "OK" for the purposes of required checks on branch
# protection, so we take advantage of this fact and fail if any of the dependent actions failed,
# or "skip" (which is a success for GHA's purposes) if none of them did.
if: failure()
steps:
- name: Dependent checks failed
run: exit 1
check-dist-up-to-date:
name: Check the dist/ folder is up to date
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Install Nix
uses: ./
with:
logger: pretty
log-directives: nix_installer=trace
backtrace: full
- name: echo $PATH
run: echo $PATH
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
nix run nixpkgs#hello
nix profile install nixpkgs#hello
hello
nix store gc
nix run nixpkgs#hello
- name: Test bash
run: nix-instantiate -E 'builtins.currentTime' --eval
if: success() || failure()
shell: bash --login {0}
- name: Test sh
run: nix-instantiate -E 'builtins.currentTime' --eval
if: success() || failure()
shell: sh -l {0}
- name: Install Nix again (noop)
uses: ./
with:
logger: pretty
log-directives: nix_installer=trace
backtrace: full
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
nix run nixpkgs#hello
nix profile install nixpkgs#hello
hello
nix store gc
nix run nixpkgs#hello
- name: Reinstall Nix
uses: ./
with:
logger: pretty
log-directives: nix_installer=trace
backtrace: full
reinstall: true
extra-conf: |
use-sqlite-wal = true
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
nix run nixpkgs#hello
nix profile install nixpkgs#hello
hello
nix store gc
nix run nixpkgs#hello
- name: Verify the generated nix.conf
run: |
cat -n /etc/nix/nix.conf
grep -E "^trusted-users = .*$USER" /etc/nix/nix.conf
grep -E "^use-sqlite-wal = true" /etc/nix/nix.conf
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/flakehub-cache-action@main
- name: pnpm install
run: nix develop --command pnpm install
- name: prettier format
run: nix develop --command pnpm run check-fmt
- name: ESLint
run: nix develop --command pnpm run lint
- name: tsup build
run: nix develop --command pnpm run build
- name: ncc package
run: nix develop --command pnpm run package
- name: Git status
run: git status --porcelain=v1
- name: Ensure no staged changes
run: git diff --exit-code
run-x86_64-darwin:
name: Run x86_64 Darwin
runs-on: macos-12
install-nix:
name: "Test: ${{ matrix.runner }}${{ matrix.determinate && ' with determinate' || '' }}"
strategy:
fail-fast: false
matrix:
runner:
- ubuntu-latest
- nscloud-ubuntu-22.04-amd64-4x16
- namespace-profile-default-arm64
# - macos-12-large # determinate-nixd is broken on macos-12
- macos-13-large
- macos-14-large
- macos-14-xlarge # arm64
determinate:
- true
- false
runs-on: ${{ matrix.runner }}
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install Nix
uses: ./
with:
logger: pretty
log-directives: nix_installer=trace
backtrace: full
_internal-strict-mode: true
determinate: ${{ matrix.determinate }}
- name: echo $PATH
run: echo $PATH
- name: Render the devshell
if: (success() || failure()) && matrix.runner != 'macos-13-large' && matrix.runner != 'macos-14-large'
run: |
nix develop --command date
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
@@ -93,6 +90,7 @@ jobs:
hello
nix store gc
nix run nixpkgs#hello
- name: Test bash
run: nix-instantiate -E 'builtins.currentTime' --eval
if: success() || failure()
@@ -102,15 +100,16 @@ jobs:
if: success() || failure()
shell: sh -l {0}
- name: Test zsh
run: nix-instantiate -E 'builtins.currentTime' --eval
run: if (zsh --help > /dev/null); then zsh --login --interactive -c "nix-instantiate -E 'builtins.currentTime' --eval"; fi
if: success() || failure()
shell: zsh --login --interactive {0}
- name: Install Nix again (noop)
uses: ./
with:
logger: pretty
log-directives: nix_installer=trace
backtrace: full
_internal-strict-mode: true
determinate: ${{ matrix.determinate }}
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
@@ -128,6 +127,8 @@ jobs:
reinstall: true
extra-conf: |
use-sqlite-wal = true
_internal-strict-mode: true
determinate: ${{ matrix.determinate }}
- name: Test `nix` with `$GITHUB_PATH`
if: success() || failure()
run: |
@@ -138,6 +139,38 @@ jobs:
nix run nixpkgs#hello
- name: Verify the generated nix.conf
run: |
cat /etc/nix/nix.conf
grep -E "^trusted-users = .*$USER" /etc/nix/nix.conf
grep -E "^use-sqlite-wal = true" /etc/nix/nix.conf
nix config show
cat -n /etc/nix/nix.conf
nix config show | grep -E "^trusted-users = .*$USER"
nix config show | grep -E "^use-sqlite-wal = true"
install-with-non-default-source-inputs:
name: Install Nix using non-default source-${{ matrix.inputs.key }}
runs-on: ubuntu-22.04
strategy:
matrix:
inputs:
# https://github.com/DeterminateSystems/nix-installer/blob/v3.11.3
- key: url
value: https://github.com/DeterminateSystems/nix-installer/releases/download/v3.11.3/nix-installer-x86_64-linux
nix-version: "2.31.2" # 3.11.3 is based on 2.31.2
steps:
- uses: actions/checkout@v4
- name: Install with alternative source-${{ matrix.inputs.key }}
uses: ./
with:
source-${{ matrix.inputs.key }}: ${{ matrix.inputs.value }}
_internal-strict-mode: true
- name: Ensure that the expected Nix version ${{ matrix.inputs.nix-version }} is installed via alternative source-${{ matrix.inputs.key }}
run: .github/verify-version.sh ${{ matrix.inputs.nix-version }}
install-no-id-token:
name: Install Nix without an ID token
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./
with:
_internal-strict-mode: true
determinate: true
+1 -1
View File
@@ -1 +1 @@
{}
{}
+5
View File
@@ -0,0 +1,5 @@
# Submitting Pull Requests
Run `pnpm install` to install necessary JS tools.
This action is based off https://github.com/actions/javascript-action. As part of your contributing flow you **must** run `npm run all` before we can merge.
+102 -52
View File
@@ -1,6 +1,20 @@
# Nix Installer Action
# The Determinate Nix Installer Action
You can use [`nix-installer`](https://github.com/DeterminateSystems/nix-installer) as a Github action like so:
Based on the [Determinate Nix Installer](https://github.com/DeterminateSystems/nix-installer), responsible for over tens of thousands of Nix installs daily.
The fast, friendly, and reliable GitHub Action to install Nix with Flakes.
## Supports
-**Accelerated KVM** on open source projects and larger runners. See [GitHub's announcement](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/) for more info.
- ✅ Linux, x86_64, aarch64, and i686
- ✅ macOS, x86_64 and aarch64
- ✅ WSL2, x86_64 and aarch64
- ✅ Containers
- ✅ Valve's SteamOS
- ✅ GitHub Enterprise Server
- ✅ GitHub Hosted, self-hosted, and long running Actions Runners
## Usage
```yaml
on:
@@ -11,18 +25,16 @@ on:
jobs:
lints:
name: Build
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Run `nix build`
run: nix build .
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- run: nix build .
```
See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for a full example.
### With FlakeHub
To use private flakes from FlakeHub, use a configuration like this:
To fetch private flakes from FlakeHub and Nix builds from FlakeHub Cache, update the `permissions` block and use [`determinate-nix-action`][determinate-nix-action]:
```yaml
on:
@@ -33,59 +45,97 @@ on:
jobs:
lints:
name: Build
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
id-token: "write"
contents: "read"
steps:
- uses: actions/checkout@v3
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
with:
flakehub: true
- name: Run `nix build`
run: nix build .
- uses: actions/checkout@v4
- uses: DeterminateSystems/determinate-nix-action@v3
- run: nix build .
```
See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for a full example.
### Pinning the version
This GitHub Action uses the most recent version of the Determinate Nix Installer, even when the Action itself is pinned.
If you wish to pin your CI workflows to a specific version, use the [`determinate-nix-action`][determinate-nix-action].
That Action is updated and tagged for every Determinate release.
The `DeterminateSystems/determinate-nix-action@v3.5.2` reference, for example, always installs Determinate Nix v3.5.2.
Additionally, an extra tag on the major version is kept up to date with the current release.
The `DeterminateSystems/determinate-nix-action@v3` reference, for example, installs the most recent release in the `v3.x.y` series.
If you do tag to a specific version, please [use Dependabot to update your actions][dependabot-actions].
### Advanced Usage
- If KVM is available, the installer sets up KVM so that Nix can use it ,and exports the `DETERMINATE_NIX_KVM` environment variable set to 1.
If KVM is not available, `DETERMINATE_NIX_KVM` is set to 0.
This can be used in combination with GitHub Actions' `if` syntax for turning on and off steps.
## Installation Differences
Differing from the upstream [Nix](https://github.com/NixOS/nix) installer scripts:
- In `nix.conf`:
- the `nix-command` and `flakes` features are enabled
- `bash-prompt-prefix` is set
- `auto-optimise-store` is set to `true` (On Linux only)
* `extra-nix-path` is set to `nixpkgs=flake:nixpkgs`
* `max-jobs` is set to `auto`
- KVM is enabled by default.
- an installation receipt (for uninstalling) is stored at `/nix/receipt.json` as well as a copy of the install binary at `/nix/nix-installer`
- `nix-channel --update` is not run, `~/.nix-channels` is not provisioned
- `ssl-cert-file` is set in `/etc/nix/nix.conf` if the `ssl-cert-file` argument is used.
## Configuration
| Parameter | Description | Type | Default |
| :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | :--------------------------------------------------- |
| `backtrace` | The setting for [`RUST_BACKTRACE`][backtrace] | string | |
| `extra-args` | Extra arguments to pass to the planner (prefer using structured `with:` arguments unless using a custom [planner]!) | string | |
| `extra-conf` | Extra configuration lines for `/etc/nix/nix.conf` (includes `access-tokens` with `secrets.GITHUB_TOKEN` automatically if `github-token` is set) | string | |
| `flakehub` | Log in to FlakeHub to pull private flakes using the GitHub Actions [JSON Web Token](https://jwt.io) (JWT), which is bound to the `api.flakehub.com` audience. | Boolean | `false` |
| `github-token` | A [GitHub token] for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests) | string | `${{ github.token }}` |
| `init` | The init system to configure (requires `planner: linux-multi`) | enum (`none` or `systemd`) | |
| `local-root` | A local `nix-installer` binary root. Overrides the `nix-installer-url` setting (a `nix-installer.sh` should exist, binaries should be named `nix-installer-$ARCH`, eg. `nix-installer-x86_64-linux`). | Boolean | `false` |
| `log-directives` | A list of [tracing directives], comma separated with `-`s replaced with `_` (eg. `nix_installer=trace`) | string | |
| `logger` | The logger to use during installation | enum (`pretty`, `json`, `full`, `compact`) | |
| `mac-case-sensitive` | Use a case-sensitive volume (`planner: macos` only) | Boolean | `false` |
| `mac-encrypt` | Force encryption on the volume (`planner: macos` only) | Boolean | `false` |
| `mac-root-disk` | The root disk of the target (`planner: macos` only) | string | |
| `mac-volume-label` | The label for the created [APFS] volume (`planner: macos` only) | string | |
| `modify-profile` | Modify the user [profile] to automatically load Nix | Boolean | `false` |
| `nix-build-group-id` | The Nix build group GID | integer | |
| `nix-build-group-name` | The Nix build group name | string | |
| `nix-build-user-base` | The Nix build user base UID (ascending) | integer | |
| `nix-build-user-count` | The number of build users to create | integer | 32 |
| `nix-build-user-prefix` | The Nix build user prefix (user numbers will be postfixed) | string | |
| `nix-installer-branch` | The branch of `nix-installer` to use (conflicts with the `nix-installer-tag`, `nix-installer-revision`, and `nix-installer-branch`) | string | |
| `nix-installer-pr` | The pull request of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-revision`, and `nix-installer-branch`) | integer | |
| `nix-installer-revision` | The revision of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-branch`, and `nix-installer-pr`) | string | |
| `nix-installer-tag` | The tag of `nix-installer` to use (conflicts with `nix-installer-revision`, `nix-installer-branch`, `nix-installer-pr`) | string | |
| `nix-installer-url` | A URL pointing to a `nix-installer.sh` script | URL | `https://install.determinate.systems/nix` |
| `nix-package-url` | The Nix package URL | URL | |
| `planner` | The installation [planner] to use | enum (`linux` or `macos`) | |
| `reinstall` | Force a reinstall if an existing installation is detected (consider backing up `/nix/store`) | Boolean | `false` |
| `start-daemon` | If the daemon should be started, requires `planner: linux-multi` | Boolean | `false` |
| `trust-runner-user` | Whether to make the runner user trusted by the Nix daemon | Boolean | `true` |
| `diagnostic-endpoint` | Diagnostic endpoint url where the installer sends install [diagnostic reports](https://github.com/DeterminateSystems/nix-installer#diagnostics) to, to disable set this to an empty string | string | `https://install.determinate.systems/nix/diagnostic` |
| `proxy` | The proxy to use (if any), valid proxy bases are `https://$URL`, `http://$URL` and `socks5://$URL` | string | |
| `ssl-cert-file` | An SSL cert to use (if any), used for fetching Nix and sets `NIX_SSL_CERT_FILE` for Nix | string | |
| Parameter | Description | Type | Default |
| :---------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | :------------------------------------------------------------- |
| `backtrace` | The setting for [`RUST_BACKTRACE`][backtrace] | string | |
| `determinate` | Whether to install [Determinate Nix](https://determinate.systems/enterprise) and log in to FlakeHub for private Flakes and binary caches. | Boolean | `true` |
| `extra-args` | Extra arguments to pass to the planner (prefer using structured `with:` arguments unless using a custom [planner]!) | string | |
| `extra-conf` | Extra configuration lines for `/etc/nix/nix.conf` (includes `access-tokens` with `secrets.GITHUB_TOKEN` automatically if `github-token` is set) | string | |
| `flakehub` | Deprecated. Implies `determinate`. | Boolean | `false` |
| `force-no-systemd` | Force using other methods than systemd to launch the daemon. This setting is automatically enabled when necessary. | Boolean | `false` |
| `github-token` | A [GitHub token] for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests) | string | `${{ github.token }}` |
| `github-server-url` | The URL for the GitHub server, to use with the `github-token` token. Defaults to the current GitHub server, supporting GitHub Enterprise Server automatically. Only change this value if the provided `github-token` is for a different GitHub server than the current server. | string | `${{ github.server }}` |
| `init` | The init system to configure (requires `planner: linux-multi`) | enum (`none` or `systemd`) | |
| `kvm` | Automatically configure the GitHub Actions Runner for NixOS test support, if the host supports it. | Boolean | `true` |
| `local-root` | A local `nix-installer` binary root. Overrides the `nix-installer-url` setting (a `nix-installer.sh` should exist, binaries should be named `nix-installer-$ARCH`, eg. `nix-installer-x86_64-linux`). | Boolean | `false` |
| `log-directives` | A list of [tracing directives], comma separated with `-`s replaced with `_` (eg. `nix_installer=trace`) | string | |
| `logger` | The logger to use during installation | enum (`pretty`, `json`, `full`, `compact`) | |
| `mac-case-sensitive` | Use a case-sensitive volume (`planner: macos` only) | Boolean | `false` |
| `mac-encrypt` | Force encryption on the volume (`planner: macos` only) | Boolean | `false` |
| `mac-root-disk` | The root disk of the target (`planner: macos` only) | string | |
| `mac-volume-label` | The label for the created [APFS] volume (`planner: macos` only) | string | |
| `modify-profile` | Modify the user [profile] to automatically load Nix | Boolean | `false` |
| `nix-build-group-id` | The Nix build group GID | integer | |
| `nix-build-group-name` | The Nix build group name | string | |
| `nix-build-user-base` | The Nix build user base UID (ascending) | integer | |
| `nix-build-user-count` | The number of build users to create | integer | 32 |
| `nix-build-user-prefix` | The Nix build user prefix (user numbers will be postfixed) | string | |
| `source-branch` | The branch of `nix-installer` to use (conflicts with the `source-tag`, `source-revision`, and `source-branch`) | string | |
| `source-pr` | The pull request of `nix-installer` to use (conflicts with `source-tag`, `source-revision`, and `source-branch`) | integer | |
| `source-revision` | The revision of `nix-installer` to use (conflicts with `source-tag`, `source-branch`, and `source-pr`) | string | |
| `source-tag` | The tag of `nix-installer` to use (conflicts with `source-revision`, `source-branch`, `source-pr`) | string | |
| `source-url` | A URL pointing to the `nix-installer` binary | URL | n/a (calculated) |
| `nix-package-url` | The Nix package URL | URL | |
| `planner` | The installation [planner] to use | enum (`linux` or `macos`) | |
| `reinstall` | Force a reinstall if an existing installation is detected (consider backing up `/nix/store`) | Boolean | `false` |
| `start-daemon` | If the daemon should be started, requires `planner: linux-multi` | Boolean | `false` |
| `trust-runner-user` | Whether to make the runner user trusted by the Nix daemon | Boolean | `true` |
| `diagnostic-endpoint` | Diagnostic endpoint url where the installer sends install [diagnostic reports](https://github.com/DeterminateSystems/nix-installer#diagnostics) to, to disable set this to an empty string | string | `https://install.determinate.systems/nix-installer/diagnostic` |
| `proxy` | The proxy to use (if any), valid proxy bases are `https://$URL`, `http://$URL` and `socks5://$URL` | string | |
| `ssl-cert-file` | An SSL cert to use (if any), used for fetching Nix and sets `NIX_SSL_CERT_FILE` for Nix | string | |
[apfs]: https://en.wikipedia.org/wiki/Apple_File_System
[backtrace]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
[dependabot-actions]: https://github.com/DeterminateSystems/determinate-nix-action?tab=readme-ov-file#-automate-updates-with-dependabot
[determinate-nix-action]: https://github.com/DeterminateSystems/determinate-nix-action
[github token]: https://docs.github.com/en/actions/security-guides/automatic-token-authentication
[planner]: https://github.com/determinateSystems/nix-installer#usage
[profile]: https://nixos.org/manual/nix/stable/package-management/profiles
+57 -16
View File
@@ -7,6 +7,10 @@ inputs:
backtrace:
description: The setting for `RUST_BACKTRACE` (see https://doc.rust-lang.org/std/backtrace/index.html#environment-variables)
required: false
determinate:
description: |
Whether to install [Determinate Nix](https://determinate.systems/enterprise) and log in to FlakeHub for private Flakes and binary caches.
default: true
extra-args:
description: Extra args to pass to the planner (prefer using structured `with:` arguments unless using a custom planner!)
required: false
@@ -14,15 +18,29 @@ inputs:
description: Extra configuration lines for `/etc/nix/nix.conf` (includes `access-tokens` with `secrets.GITHUB_TOKEN` automatically if `github-token` is set)
required: false
flakehub:
description: Automatically log in to your [FlakeHub](https://flakehub.com) account, for accessing private flakes.
description: Deprecated. Implies `determinate`.
required: false
default: false
force-no-systemd:
description: Force using other methods than systemd to launch the daemon. This setting is automatically enabled when necessary.
required: false
default: false
github-token:
description: A GitHub token for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests)
default: ${{ github.token }}
github-server-url:
description: The URL for the GitHub server, to use with the `github-token` token. Defaults to the current GitHub server, supporting GitHub Enterprise Server automatically. Only change this value if the provided `github-token` is for a different GitHub server than the current server.
default: ${{ github.server_url }}
init:
description: "The init system to configure, requires `planner: linux-multi` (allowing the choice between `none` or `systemd`)"
required: false
job-status:
description: The overall status of the job. Set automatically, for aggregate analysis of Nix stability.
default: ${{ job.status }}
kvm:
description: Automatically configure the GitHub Actions Runner for NixOS test supports, if the host supports it.
required: false
default: true
local-root:
description: A local `nix-installer` binary root, overrides any settings which change the `nix-installer` used (binaries should be named `nix-installer-$ARCH-$OS`, eg. `nix-installer-x86_64-linux`)
required: false
@@ -69,20 +87,23 @@ inputs:
nix-build-user-prefix:
description: The Nix build user prefix (user numbers will be postfixed)
required: false
nix-installer-branch:
description: The branch of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-revision`, `nix-installer-pr`)
source-binary:
description: Run a version of the nix-installer binary from somewhere already on disk. Conflicts with all other `source-*` options. Intended only for testing this Action.
required: false
nix-installer-pr:
description: The PR of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-revision`, `nix-installer-branch`)
source-branch:
description: The branch of `nix-installer` to use (conflicts with `source-tag`, `source-revision`, `source-pr`)
required: false
nix-installer-revision:
description: The revision of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-branch`, `nix-installer-pr`)
source-pr:
description: The PR of `nix-installer` to use (conflicts with `source-tag`, `source-revision`, `source-branch`)
required: false
nix-installer-tag:
description: The tag of `nix-installer` to use (conflicts with `nix-installer-revision`, `nix-installer-branch`, `nix-installer-pr`)
source-revision:
description: The revision of `nix-installer` to use (conflicts with `source-tag`, `source-branch`, `source-pr`)
required: false
nix-installer-url:
description: A URL pointing to a `nix-installer.sh` script
source-tag:
description: The tag of `nix-installer` to use (conflicts with `source-revision`, `source-branch`, `source-pr`)
required: false
source-url:
description: A URL pointing to a `nix-installer` executable
required: false
nix-package-url:
description: The Nix package URL
@@ -100,12 +121,32 @@ inputs:
default: true
diagnostic-endpoint:
description: "Diagnostic endpoint url where the installer sends data to. To disable set this to an empty string."
default: "https://install.determinate.systems/nix/diagnostic"
required: false
default: "-"
trust-runner-user:
description: Whether to make the runner user trusted by the Nix daemon
default: "true"
default: true
nix-installer-branch:
description: (deprecated) The branch of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-revision`, `nix-installer-pr`)
required: false
nix-installer-pr:
description: (deprecated) The PR of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-revision`, `nix-installer-branch`)
required: false
nix-installer-revision:
description: (deprecated) The revision of `nix-installer` to use (conflicts with `nix-installer-tag`, `nix-installer-branch`, `nix-installer-pr`)
required: false
nix-installer-tag:
description: (deprecated) The tag of `nix-installer` to use (conflicts with `nix-installer-revision`, `nix-installer-branch`, `nix-installer-pr`)
required: false
nix-installer-url:
description: (deprecated) A URL pointing to a `nix-installer.sh` script
required: false
_internal-strict-mode:
description: Whether to fail when any errors are thrown. Used only to test the Action; do not set this in your own workflows.
required: false
default: false
runs:
using: "node16"
main: 'dist/index.js'
post: 'dist/index.js'
using: "node20"
main: "dist/index.js"
post: "dist/index.js"
Generated Vendored
-453
View File
@@ -1,453 +0,0 @@
"use strict";
exports.id = 37;
exports.ids = [37];
exports.modules = {
/***/ 4037:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
/* harmony export */ });
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2185);
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8010);
let s = 0;
const S = {
START_BOUNDARY: s++,
HEADER_FIELD_START: s++,
HEADER_FIELD: s++,
HEADER_VALUE_START: s++,
HEADER_VALUE: s++,
HEADER_VALUE_ALMOST_DONE: s++,
HEADERS_ALMOST_DONE: s++,
PART_DATA_START: s++,
PART_DATA: s++,
END: s++
};
let f = 1;
const F = {
PART_BOUNDARY: f,
LAST_BOUNDARY: f *= 2
};
const LF = 10;
const CR = 13;
const SPACE = 32;
const HYPHEN = 45;
const COLON = 58;
const A = 97;
const Z = 122;
const lower = c => c | 0x20;
const noop = () => {};
class MultipartParser {
/**
* @param {string} boundary
*/
constructor(boundary) {
this.index = 0;
this.flags = 0;
this.onHeaderEnd = noop;
this.onHeaderField = noop;
this.onHeadersEnd = noop;
this.onHeaderValue = noop;
this.onPartBegin = noop;
this.onPartData = noop;
this.onPartEnd = noop;
this.boundaryChars = {};
boundary = '\r\n--' + boundary;
const ui8a = new Uint8Array(boundary.length);
for (let i = 0; i < boundary.length; i++) {
ui8a[i] = boundary.charCodeAt(i);
this.boundaryChars[ui8a[i]] = true;
}
this.boundary = ui8a;
this.lookbehind = new Uint8Array(this.boundary.length + 8);
this.state = S.START_BOUNDARY;
}
/**
* @param {Uint8Array} data
*/
write(data) {
let i = 0;
const length_ = data.length;
let previousIndex = this.index;
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
const boundaryLength = this.boundary.length;
const boundaryEnd = boundaryLength - 1;
const bufferLength = data.length;
let c;
let cl;
const mark = name => {
this[name + 'Mark'] = i;
};
const clear = name => {
delete this[name + 'Mark'];
};
const callback = (callbackSymbol, start, end, ui8a) => {
if (start === undefined || start !== end) {
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
}
};
const dataCallback = (name, clear) => {
const markSymbol = name + 'Mark';
if (!(markSymbol in this)) {
return;
}
if (clear) {
callback(name, this[markSymbol], i, data);
delete this[markSymbol];
} else {
callback(name, this[markSymbol], data.length, data);
this[markSymbol] = 0;
}
};
for (i = 0; i < length_; i++) {
c = data[i];
switch (state) {
case S.START_BOUNDARY:
if (index === boundary.length - 2) {
if (c === HYPHEN) {
flags |= F.LAST_BOUNDARY;
} else if (c !== CR) {
return;
}
index++;
break;
} else if (index - 1 === boundary.length - 2) {
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
state = S.END;
flags = 0;
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
index = 0;
callback('onPartBegin');
state = S.HEADER_FIELD_START;
} else {
return;
}
break;
}
if (c !== boundary[index + 2]) {
index = -2;
}
if (c === boundary[index + 2]) {
index++;
}
break;
case S.HEADER_FIELD_START:
state = S.HEADER_FIELD;
mark('onHeaderField');
index = 0;
// falls through
case S.HEADER_FIELD:
if (c === CR) {
clear('onHeaderField');
state = S.HEADERS_ALMOST_DONE;
break;
}
index++;
if (c === HYPHEN) {
break;
}
if (c === COLON) {
if (index === 1) {
// empty header field
return;
}
dataCallback('onHeaderField', true);
state = S.HEADER_VALUE_START;
break;
}
cl = lower(c);
if (cl < A || cl > Z) {
return;
}
break;
case S.HEADER_VALUE_START:
if (c === SPACE) {
break;
}
mark('onHeaderValue');
state = S.HEADER_VALUE;
// falls through
case S.HEADER_VALUE:
if (c === CR) {
dataCallback('onHeaderValue', true);
callback('onHeaderEnd');
state = S.HEADER_VALUE_ALMOST_DONE;
}
break;
case S.HEADER_VALUE_ALMOST_DONE:
if (c !== LF) {
return;
}
state = S.HEADER_FIELD_START;
break;
case S.HEADERS_ALMOST_DONE:
if (c !== LF) {
return;
}
callback('onHeadersEnd');
state = S.PART_DATA_START;
break;
case S.PART_DATA_START:
state = S.PART_DATA;
mark('onPartData');
// falls through
case S.PART_DATA:
previousIndex = index;
if (index === 0) {
// boyer-moore derrived algorithm to safely skip non-boundary data
i += boundaryEnd;
while (i < bufferLength && !(data[i] in boundaryChars)) {
i += boundaryLength;
}
i -= boundaryEnd;
c = data[i];
}
if (index < boundary.length) {
if (boundary[index] === c) {
if (index === 0) {
dataCallback('onPartData', true);
}
index++;
} else {
index = 0;
}
} else if (index === boundary.length) {
index++;
if (c === CR) {
// CR = part boundary
flags |= F.PART_BOUNDARY;
} else if (c === HYPHEN) {
// HYPHEN = end boundary
flags |= F.LAST_BOUNDARY;
} else {
index = 0;
}
} else if (index - 1 === boundary.length) {
if (flags & F.PART_BOUNDARY) {
index = 0;
if (c === LF) {
// unset the PART_BOUNDARY flag
flags &= ~F.PART_BOUNDARY;
callback('onPartEnd');
callback('onPartBegin');
state = S.HEADER_FIELD_START;
break;
}
} else if (flags & F.LAST_BOUNDARY) {
if (c === HYPHEN) {
callback('onPartEnd');
state = S.END;
flags = 0;
} else {
index = 0;
}
} else {
index = 0;
}
}
if (index > 0) {
// when matching a possible boundary, keep a lookbehind reference
// in case it turns out to be a false lead
lookbehind[index - 1] = c;
} else if (previousIndex > 0) {
// if our boundary turned out to be rubbish, the captured lookbehind
// belongs to partData
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
callback('onPartData', 0, previousIndex, _lookbehind);
previousIndex = 0;
mark('onPartData');
// reconsider the current character even so it interrupted the sequence
// it could be the beginning of a new sequence
i--;
}
break;
case S.END:
break;
default:
throw new Error(`Unexpected state entered: ${state}`);
}
}
dataCallback('onHeaderField');
dataCallback('onHeaderValue');
dataCallback('onPartData');
// Update properties for the next call
this.index = index;
this.state = state;
this.flags = flags;
}
end() {
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
this.onPartEnd();
} else if (this.state !== S.END) {
throw new Error('MultipartParser.end(): stream ended unexpectedly');
}
}
}
function _fileName(headerValue) {
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
if (!m) {
return;
}
const match = m[2] || m[3] || '';
let filename = match.slice(match.lastIndexOf('\\') + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
return String.fromCharCode(code);
});
return filename;
}
async function toFormData(Body, ct) {
if (!/multipart/i.test(ct)) {
throw new TypeError('Failed to fetch');
}
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
if (!m) {
throw new TypeError('no or bad content-type header, no multipart boundary');
}
const parser = new MultipartParser(m[1] || m[2]);
let headerField;
let headerValue;
let entryValue;
let entryName;
let contentType;
let filename;
const entryChunks = [];
const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
const onPartData = ui8a => {
entryValue += decoder.decode(ui8a, {stream: true});
};
const appendToFile = ui8a => {
entryChunks.push(ui8a);
};
const appendFileToFormData = () => {
const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
formData.append(entryName, file);
};
const appendEntryToFormData = () => {
formData.append(entryName, entryValue);
};
const decoder = new TextDecoder('utf-8');
decoder.decode();
parser.onPartBegin = function () {
parser.onPartData = onPartData;
parser.onPartEnd = appendEntryToFormData;
headerField = '';
headerValue = '';
entryValue = '';
entryName = '';
contentType = '';
filename = null;
entryChunks.length = 0;
};
parser.onHeaderField = function (ui8a) {
headerField += decoder.decode(ui8a, {stream: true});
};
parser.onHeaderValue = function (ui8a) {
headerValue += decoder.decode(ui8a, {stream: true});
};
parser.onHeaderEnd = function () {
headerValue += decoder.decode();
headerField = headerField.toLowerCase();
if (headerField === 'content-disposition') {
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
if (m) {
entryName = m[2] || m[3] || '';
}
filename = _fileName(headerValue);
if (filename) {
parser.onPartData = appendToFile;
parser.onPartEnd = appendFileToFormData;
}
} else if (headerField === 'content-type') {
contentType = headerValue;
}
headerValue = '';
headerField = '';
};
for await (const chunk of Body) {
parser.write(chunk);
}
parser.end();
return formData;
}
/***/ })
};
;
//# sourceMappingURL=37.index.js.map
Generated Vendored
-1
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+2
View File
@@ -0,0 +1,2 @@
export { }
Generated Vendored
+98185 -13537
View File
File diff suppressed because one or more lines are too long
Generated Vendored
-1
View File
File diff suppressed because one or more lines are too long
Generated Vendored
-23
View File
@@ -1,23 +0,0 @@
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 David Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Generated Vendored
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
Generated Vendored
-1
View File
File diff suppressed because one or more lines are too long
Generated
+7 -5
View File
@@ -2,6 +2,7 @@
"nodes": {
"flake-schemas": {
"locked": {
"lastModified": 1693491534,
"narHash": "sha256-ifw8Td8kD08J8DxFbYjeIx5naHcDLz7s2IFP3X42I/U=",
"rev": "c702cbb663d6d70bbb716584a2ee3aeb35017279",
"revCount": 21,
@@ -15,15 +16,16 @@
},
"nixpkgs": {
"locked": {
"narHash": "sha256-g7nIUV4uq1TOVeVIDEZLb005suTWCUjSY0zYOlSBsyE=",
"rev": "32dcb45f66c0487e92db8303a798ebc548cadedc",
"revCount": 491340,
"lastModified": 1696879762,
"narHash": "sha256-Ud6bH4DMcYHUDKavNMxAhcIpDGgHMyL/yaDEAVSImQY=",
"rev": "f99e5f03cc0aa231ab5950a15ed02afec45ed51a",
"revCount": 534224,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2305.491340%2Brev-32dcb45f66c0487e92db8303a798ebc548cadedc/018aebfc-faf0-743e-aeb4-28acf5a64d95/source.tar.gz"
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.534224%2Brev-f99e5f03cc0aa231ab5950a15ed02afec45ed51a/018b1d3c-12f0-76a5-b796-7668d7633f08/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/NixOS/nixpkgs/%2A.tar.gz"
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.1.0.tar.gz"
}
},
"root": {
+5 -3
View File
@@ -4,12 +4,12 @@
inputs = {
flake-schemas.url = "https://flakehub.com/f/DeterminateSystems/flake-schemas/*.tar.gz";
nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/*.tar.gz";
nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.0.tar.gz";
};
outputs = { self, flake-schemas, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-darwin" ];
supportedSystems = [ "x86_64-linux" "aarch64-darwin" "aarch64-linux" ];
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
pkgs = import nixpkgs { inherit system; };
});
@@ -20,8 +20,10 @@
devShells = forEachSupportedSystem ({ pkgs }: {
default = pkgs.mkShell {
packages = with pkgs; [
nodejs-18_x
nodejs_latest
nixpkgs-fmt
nodePackages_latest.pnpm
nodePackages_latest.typescript-language-server
];
};
});
-6222
View File
File diff suppressed because it is too large Load Diff
+30 -19
View File
@@ -1,14 +1,18 @@
{
"name": "nix-installer-action",
"version": "1.0.0",
"description": "You can use [`nix-installer`](https://github.com/DeterminateSystems/nix-installer) as a Github action:",
"main": "lib/main.js",
"description": "You can use [`nix-installer`](https://github.com/DeterminateSystems/nix-installer) as a Github Action:",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"scripts": {
"build": "tsc",
"format": "prettier --write '**/*.ts'",
"build": "tsup",
"format": "prettier --write .",
"check-fmt": "prettier --check .",
"lint": "eslint src/**/*.ts",
"package": "ncc build --source-map --license licenses.txt",
"all": "npm run build && npm run format && npm run lint && npm run package"
"package": "ncc build",
"test": "vitest --watch false",
"all": "pnpm run test && pnpm run format && pnpm run lint && pnpm run build && pnpm run package"
},
"repository": {
"type": "git",
@@ -22,20 +26,27 @@
},
"homepage": "https://github.com/DeterminateSystems/nix-installer-action#readme",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"node-fetch": "^3.3.1",
"string-argv": "^0.3.2"
"@actions/core": "^1.11.1",
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.1",
"detsys-ts": "github:DeterminateSystems/detsys-ts",
"got": "^14.6.2",
"string-argv": "^0.3.2",
"vitest": "^3.2.4"
},
"devDependencies": {
"@types/node": "^18.16.3",
"@typescript-eslint/parser": "^5.59.2",
"@vercel/ncc": "^0.36.1",
"eslint": "^8.44.0",
"eslint-plugin-github": "^4.3.6",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^5.0.0-alpha.1",
"prettier": "^3.0.0",
"typescript": "^5.1.6"
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/node": "^20.19.24",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@vercel/ncc": "^0.38.4",
"eslint": "^8.57.1",
"eslint-import-resolver-typescript": "^3.10.1",
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"prettier": "^3.6.2",
"tsup": "^8.5.0",
"typescript": "^5.9.3"
}
}
+6478
View File
File diff suppressed because it is too large Load Diff
+66
View File
@@ -0,0 +1,66 @@
import * as core from "@actions/core";
import type { Fix, FixHashesOutputV1, Mismatch } from "./fixHashes.js";
function prettyDerivation(derivation: string): string {
return derivation.replace(/\/nix\/store\/\w+-/, "").replace(/.drv$/, "");
}
function annotateSingle(
file: string,
line: number,
{ derivation, replacement }: Mismatch,
): void {
const pretty = prettyDerivation(derivation);
core.error(`To correct the hash mismatch for ${pretty}, use ${replacement}`, {
file,
startLine: line,
});
}
function annotateMultiple(
file: string,
{ line, found, mismatches }: Fix,
): void {
const matches = mismatches
.map(({ derivation, replacement }) => {
const pretty = prettyDerivation(derivation);
return `* For the derivation ${pretty}, use ${replacement}`;
})
.join("\n");
core.error(
`There are multiple replacements for the expression ${found}:\n${matches}`,
{
file,
startLine: line,
},
);
}
function annotate(file: string, fix: Fix): void {
if (fix.mismatches.length === 1) {
annotateSingle(file, fix.line, fix.mismatches[0]);
} else {
annotateMultiple(file, fix);
}
}
/**
* Annotates fixed-output derivation hash mismatches using GitHub Actions'
*
* @param output The output of `determinate-nixd fix hashes --json`
* @returns The number of annotations reported to the user
*/
export function annotateMismatches(output: FixHashesOutputV1): number {
let count = 0;
for (const { file, fixes } of output.files) {
for (const fix of fixes) {
annotate(file, fix);
count++;
}
}
return count;
}
+65
View File
@@ -0,0 +1,65 @@
import { parseEvents, getRecentEvents } from "./events.js";
import { expect, test } from "vitest";
// Handy test for locally making sure you can fetch recent events:
// eslint-disable-next-line no-constant-condition
if (false) {
test("Parsing existing events", async () => {
expect(await getRecentEvents(new Date(Date.now() - 1000000))).toStrictEqual(
[{}],
);
});
}
test("Parsing existing events", () => {
const { events } = parseEvents([
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/m96zgji4fhi70s2zs6pq5pric6ch7p4h-stdenv-darwin.drv",
outputs: ["/nix/store/dalhfz3l75w4b4q06sxzqgb2wfydvkbv-stdenv-darwin"],
timing: null,
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv",
outputs: ["/nix/store/qwlgz5da3pfb53gqpgdmazaj9jczrnly-dep-1"],
timing: {
startTime: "2025-04-11T14:38:02Z",
stopTime: "2025-04-11T14:38:05Z",
durationSeconds: 3,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: "/nix/store/ykvbksjqrza2zpj6nkbycrdfwgfdpr8g-hash-mismatch-md5-base16.drv",
timing: {
startTime: "2025-04-11T14:36:44Z",
stopTime: "2025-04-11T14:36:44Z",
durationSeconds: 0,
},
},
]);
expect(events).toStrictEqual([
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv",
timing: {
durationSeconds: 3,
startTime: new Date("2025-04-11T14:38:02Z"),
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: "/nix/store/ykvbksjqrza2zpj6nkbycrdfwgfdpr8g-hash-mismatch-md5-base16.drv",
timing: {
durationSeconds: 0,
startTime: new Date("2025-04-11T14:36:44Z"),
},
},
]);
});
+89
View File
@@ -0,0 +1,89 @@
import got from "got";
export interface DEvent {
v: string;
c: string;
drv: string;
timing: {
startTime: Date;
durationSeconds: number;
};
}
export interface ParsedEventsResult {
readonly events: DEvent[];
readonly hasMismatches: boolean;
}
export function parseEvents(data: unknown): ParsedEventsResult {
let hasMismatches = false;
if (!Array.isArray(data)) {
return { events: [], hasMismatches };
}
const events = data.flatMap((event) => {
// If this was a hash mismatch event, note it and move on
if (event.v === "1" && event.c === "HashMismatchResponseEventV1") {
hasMismatches = true;
return [];
}
// Otherwise, determine if it's an event we're interested in
if (
event.v === "1" &&
(event.c === "BuildFailureResponseEventV1" ||
event.c === "BuiltPathResponseEventV1") &&
Object.hasOwn(event, "drv") &&
typeof event.drv === "string" &&
Object.hasOwn(event, "timing") &&
typeof event.timing === "object" &&
event.timing !== null
) {
const timing = event.timing as { [key: string]: unknown };
if (
Object.hasOwn(timing, "startTime") &&
typeof timing.startTime === "string" &&
Object.hasOwn(timing, "durationSeconds") &&
typeof timing.durationSeconds === "number"
) {
const date = Date.parse(timing.startTime);
if (!Number.isNaN(date)) {
return [
{
v: event.v,
c: event.c,
drv: event.drv,
timing: {
startTime: new Date(date),
durationSeconds: timing.durationSeconds,
},
},
];
}
}
}
return [];
});
return { events, hasMismatches };
}
export async function getRecentEvents(
since: Date,
): Promise<ParsedEventsResult> {
const queryParam = encodeURIComponent(since.toISOString());
const resp = await got
.get(
`http://unix:/nix/var/determinate/determinate-nixd.socket:/events/recent?since=${queryParam}`,
{
enableUnixSockets: true,
},
)
.json();
return parseEvents(resp);
}
+275
View File
@@ -0,0 +1,275 @@
import { expect, test } from "vitest";
import {
FailureSummary,
getBuildFailures,
summarizeFailures,
} from "./failuresummary.js";
/* eslint-disable @typescript-eslint/no-non-null-assertion */
test("Select for failure events", () => {
const events = [
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv`,
timing: {
startTime: new Date(1 * 1000),
durationSeconds: 1,
},
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-2.drv`,
timing: {
startTime: new Date(2 * 1000),
durationSeconds: 2,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv`,
timing: {
startTime: new Date(3 * 1000),
durationSeconds: 3,
},
},
];
expect(getBuildFailures(events)).toStrictEqual([
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv`,
timing: {
startTime: new Date(1 * 1000),
durationSeconds: 1,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv`,
timing: {
startTime: new Date(3 * 1000),
durationSeconds: 3,
},
},
]);
});
test("Summarize Failures", async () => {
const events = [
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv`,
timing: {
startTime: new Date(1 * 1000),
durationSeconds: 1,
},
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-2.drv`,
timing: {
startTime: new Date(2 * 1000),
durationSeconds: 2,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv`,
timing: {
startTime: new Date(3 * 1000),
durationSeconds: 3,
},
},
];
const logMaker = async (drv: string): Promise<string | undefined> => {
if (drv.includes("dep-1")) {
return `${drv}\n`.repeat(9).trimEnd();
} else {
return `${drv}\n`.repeat(25).trimEnd();
}
};
const summary: FailureSummary = (await summarizeFailures(events, logMaker))!;
expect(summary.markdownLines.join("\n"))
.toStrictEqual(`### Build error review :boom:
> [!NOTE]
> 2 builds failed
<details><summary>Failure log: <code>/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-<strong>dep-1</strong>.drv</code></summary>
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
</details>
<details><summary>Failure log: <code>/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-<strong>dep-3</strong>.drv</code></summary>
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
</details>
`);
expect(summary.logLines.join("\n"))
.toStrictEqual(`\u001b[38;2;255;0;0mBuild logs from 2 failures
The following build logs are also available in the Markdown summary:
::group::Failed build: /nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
::endgroup::
::group::Failed build: /nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
::endgroup::`);
});
test("Omit some logs if there are too many", async () => {
const events = [
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv`,
timing: {
startTime: new Date(1 * 1000),
durationSeconds: 1,
},
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-2.drv`,
timing: {
startTime: new Date(2 * 1000),
durationSeconds: 2,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv`,
timing: {
startTime: new Date(3 * 1000),
durationSeconds: 3,
},
},
];
const logMaker = async (drv: string): Promise<string | undefined> => {
return `${drv}\n`.repeat(5).trimEnd();
};
const summary: FailureSummary = (await summarizeFailures(
events,
logMaker,
500,
))!;
expect(summary.markdownLines.join("\n"))
.toStrictEqual(`### Build error review :boom:
> [!NOTE]
> 2 builds failed
<details><summary>Failure log: <code>/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-<strong>dep-1</strong>.drv</code></summary>
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
</details>
> [!NOTE]
> The following failure has been omitted due to GitHub Actions' summary length limitations.
> The full logs are available in the post-run phase of the Nix Installer Action.
> * \`/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv\``);
expect(summary.logLines.join("\n"))
.toStrictEqual(`\u001b[38;2;255;0;0mBuild logs from 2 failures
The following build logs are also available in the Markdown summary:
::group::Failed build: /nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv
::endgroup::
The following build logs are NOT available in the Markdown summary:
::group::Failed build: /nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-3.drv
::endgroup::`);
});
+124
View File
@@ -0,0 +1,124 @@
import { getExecOutput } from "@actions/exec";
import { DEvent } from "./events.js";
import { stripVTControlCharacters } from "node:util";
// CI summaries have a max length of "1024k" which I assume to be 1048576 bytes.
// Generously, the mermaid doc is about 50,000 bytes.
// Rounding it all down a bit further for wiggle room, that leaves lots of log space.
const defaultMaxSummaryLength = 995_000;
export function getBuildFailures(events: DEvent[]): DEvent[] {
return events.filter((event: DEvent): Boolean => {
return event.c === "BuildFailureResponseEventV1";
});
}
export interface FailureSummary {
logLines: string[];
markdownLines: string[];
}
export async function summarizeFailures(
events: DEvent[],
getLog: (drv: string) => Promise<string | undefined> = getLogFromNix,
maxLength: number = defaultMaxSummaryLength,
): Promise<FailureSummary | undefined> {
const failures = getBuildFailures(events);
if (failures.length === 0) {
return undefined;
}
const logLines = [];
const markdownLines = [];
logLines.push(
`\u001b[38;2;255;0;0mBuild logs from ${failures.length} failure${failures.length === 1 ? "" : "s"}`,
);
logLines.push(
`The following build logs are also available in the Markdown summary:`,
);
markdownLines.push(`### Build error review :boom:`);
markdownLines.push("> [!NOTE]");
markdownLines.push(
`> ${failures.length} build${failures.length === 1 ? "" : "s"} failed`,
);
const markdownLogChunks: {
drv: string;
txtLines: string[];
mdLines: string[];
}[] = [];
for (const event of failures) {
const markdownLogChunk = [];
const txtLogChunk = [];
txtLogChunk.push(`::group::Failed build: ${event.drv}`);
const log =
(await getLog(event.drv)) ??
"(failure reading the log for this derivation.)";
const indented = log.split("\n").map((line) => ` ${line}`);
markdownLogChunk.push(
`<details><summary>Failure log: <code>${event.drv.replace(/^(\/nix[^-]*-)(.*)(\.drv)$/, "$1<strong>$2</strong>$3")}</code></summary>`,
);
markdownLogChunk.push("");
for (const line of indented) {
txtLogChunk.push(line);
markdownLogChunk.push(stripVTControlCharacters(line));
}
markdownLogChunk.push("");
markdownLogChunk.push("</details>");
markdownLogChunk.push("");
markdownLogChunks.push({
drv: event.drv,
mdLines: markdownLogChunk,
txtLines: txtLogChunk,
});
txtLogChunk.push(`::endgroup::`);
}
const skippedChunks = [];
// Add markdown log chunks until we exceed the max length
let markdownLength = markdownLines.join("\n").length;
for (const chunk of markdownLogChunks) {
const chunkLength = chunk.mdLines.join("\n").length;
if (markdownLength + chunkLength > maxLength) {
skippedChunks.push(chunk);
} else {
logLines.push(...chunk.txtLines);
markdownLines.push(...chunk.mdLines);
markdownLength += chunkLength;
}
}
if (skippedChunks.length > 0) {
markdownLines.push(
"",
"> [!NOTE]",
`> The following ${skippedChunks.length === 1 ? "failure has" : "failures have"} been omitted due to GitHub Actions' summary length limitations.`,
"> The full logs are available in the post-run phase of the Nix Installer Action.",
);
logLines.push(
"The following build logs are NOT available in the Markdown summary:",
);
for (const chunk of skippedChunks) {
markdownLines.push(`> * \`${chunk.drv}\``);
logLines.push(...chunk.txtLines);
}
}
return { logLines, markdownLines };
}
async function getLogFromNix(drv: string): Promise<string | undefined> {
const output = await getExecOutput("nix", ["log", drv], {
silent: true,
});
return output.stdout;
}
+38
View File
@@ -0,0 +1,38 @@
import { getExecOutput } from "@actions/exec";
export interface Mismatch {
readonly derivation: string;
readonly replacement: string;
}
export interface Fix {
readonly line: number;
readonly found: string;
readonly mismatches: readonly Mismatch[];
}
export interface FileFix {
readonly file: string;
readonly fixes: readonly Fix[];
}
export interface FixHashesOutputV1 {
readonly version: "v1";
readonly files: readonly FileFix[];
}
export async function getFixHashes(since: string): Promise<FixHashesOutputV1> {
const output = await getExecOutput(
"determinate-nixd",
["fix", "hashes", "--json", "--since", since],
{ silent: true },
);
if (output.exitCode !== 0) {
throw new Error(
`determinate-nixd fix hashes returned non-zero exit code ${output.exitCode} with the following error output:\n${output.stderr}`,
);
}
return JSON.parse(output.stdout);
}
+1085
View File
File diff suppressed because it is too large Load Diff
-684
View File
@@ -1,684 +0,0 @@
import * as actions_core from "@actions/core";
import * as github from "@actions/github";
import { mkdtemp, chmod, access, writeFile } from "node:fs/promises";
import { spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { pipeline } from "node:stream";
import fetch from "node-fetch";
import { promisify } from "node:util";
import fs from "node:fs";
import stringArgv from "string-argv";
class NixInstallerAction {
platform: string;
nix_package_url: string | null;
backtrace: string | null;
extra_args: string | null;
extra_conf: string[] | null;
flakehub: boolean;
github_token: string | null;
// TODO: linux_init
init: string | null;
local_root: string | null;
log_directives: string | null;
logger: string | null;
ssl_cert_file: string | null;
proxy: string | null;
mac_case_sensitive: string | null;
mac_encrypt: string | null;
mac_root_disk: string | null;
mac_volume_label: string | null;
modify_profile: boolean;
nix_build_group_id: number | null;
nix_build_group_name: string | null;
nix_build_user_base: number | null;
nix_build_user_count: number | null;
nix_build_user_prefix: string | null;
planner: string | null;
reinstall: boolean;
start_daemon: boolean;
diagnostic_endpoint: string | null;
trust_runner_user: boolean | null;
nix_installer_url: URL;
// Connects the installation diagnostic report to the post-run diagnostic report.
// This is for monitoring the real impact of Nix updates, to avoid breaking large
// swaths of users at once with botched Nix releases. For example:
// https://github.com/NixOS/nix/issues/9052.
correlation: string | undefined;
constructor() {
this.platform = get_nix_platform();
this.nix_package_url = action_input_string_or_null("nix-package-url");
this.backtrace = action_input_string_or_null("backtrace");
this.extra_args = action_input_string_or_null("extra-args");
this.extra_conf = action_input_multiline_string_or_null("extra-conf");
this.flakehub = action_input_bool("flakehub");
this.github_token = action_input_string_or_null("github-token");
this.init = action_input_string_or_null("init");
this.local_root = action_input_string_or_null("local-root");
this.log_directives = action_input_string_or_null("log-directives");
this.logger = action_input_string_or_null("logger");
this.ssl_cert_file = action_input_string_or_null("ssl-cert-file");
this.proxy = action_input_string_or_null("proxy");
this.mac_case_sensitive = action_input_string_or_null("mac-case-sensitive");
this.mac_encrypt = action_input_string_or_null("mac-encrypt");
this.mac_root_disk = action_input_string_or_null("mac-root-disk");
this.mac_volume_label = action_input_string_or_null("mac-volume-label");
this.modify_profile = action_input_bool("modify-profile");
this.nix_build_group_id = action_input_number_or_null("nix-build-group-id");
this.nix_build_group_name = action_input_string_or_null(
"nix-build-group-name",
);
this.nix_build_user_base = action_input_number_or_null(
"nix_build-user-base",
);
this.nix_build_user_count = action_input_number_or_null(
"nix-build-user-count",
);
this.nix_build_user_prefix = action_input_string_or_null(
"nix-build-user-prefix",
);
this.planner = action_input_string_or_null("planner");
this.reinstall = action_input_bool("reinstall");
this.start_daemon = action_input_bool("start-daemon");
this.diagnostic_endpoint = action_input_string_or_null(
"diagnostic-endpoint",
);
this.trust_runner_user = action_input_bool("trust-runner-user");
this.correlation = process.env["STATE_correlation"];
this.nix_installer_url = resolve_nix_installer_url(
this.platform,
this.correlation,
);
}
private async executionEnvironment(): Promise<ExecuteEnvironment> {
const execution_env: ExecuteEnvironment = {};
execution_env.NIX_INSTALLER_NO_CONFIRM = "true";
execution_env.NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION = this.correlation;
if (this.backtrace !== null) {
execution_env.RUST_BACKTRACE = this.backtrace;
}
if (this.modify_profile !== null) {
if (this.modify_profile) {
execution_env.NIX_INSTALLER_MODIFY_PROFILE = "true";
} else {
execution_env.NIX_INSTALLER_MODIFY_PROFILE = "false";
}
}
if (this.nix_build_group_id !== null) {
execution_env.NIX_INSTALLER_NIX_BUILD_GROUP_ID = `${this.nix_build_group_id}`;
}
if (this.nix_build_group_name !== null) {
execution_env.NIX_INSTALLER_NIX_BUILD_GROUP_NAME =
this.nix_build_group_name;
}
if (this.nix_build_user_prefix !== null) {
execution_env.NIX_INSTALLER_NIX_BUILD_USER_PREFIX =
this.nix_build_user_prefix;
}
if (this.nix_build_user_count !== null) {
execution_env.NIX_INSTALLER_NIX_BUILD_USER_COUNT = `${this.nix_build_user_count}`;
}
if (this.nix_build_user_base !== null) {
execution_env.NIX_INSTALLER_NIX_BUILD_USER_ID_BASE = `${this.nix_build_user_count}`;
}
if (this.nix_package_url !== null) {
execution_env.NIX_INSTALLER_NIX_PACKAGE_URL = `${this.nix_package_url}`;
}
if (this.proxy !== null) {
execution_env.NIX_INSTALLER_PROXY = this.proxy;
}
if (this.ssl_cert_file !== null) {
execution_env.NIX_INSTALLER_SSL_CERT_FILE = this.ssl_cert_file;
}
if (this.diagnostic_endpoint !== null) {
execution_env.NIX_INSTALLER_DIAGNOSTIC_ENDPOINT =
this.diagnostic_endpoint;
}
// TODO: Error if the user uses these on not-MacOS
if (this.mac_encrypt !== null) {
if (process.env.RUNNER_OS !== "macOS") {
throw new Error("`mac-encrypt` while `$RUNNER_OS` was not `macOS`");
}
execution_env.NIX_INSTALLER_ENCRYPT = this.mac_encrypt;
}
if (this.mac_case_sensitive !== null) {
if (process.env.RUNNER_OS !== "macOS") {
throw new Error(
"`mac-case-sensitive` while `$RUNNER_OS` was not `macOS`",
);
}
execution_env.NIX_INSTALLER_CASE_SENSITIVE = this.mac_case_sensitive;
}
if (this.mac_volume_label !== null) {
if (process.env.RUNNER_OS !== "macOS") {
throw new Error(
"`mac-volume-label` while `$RUNNER_OS` was not `macOS`",
);
}
execution_env.NIX_INSTALLER_VOLUME_LABEL = this.mac_volume_label;
}
if (this.mac_root_disk !== null) {
if (process.env.RUNNER_OS !== "macOS") {
throw new Error("`mac-root-disk` while `$RUNNER_OS` was not `macOS`");
}
execution_env.NIX_INSTALLER_ROOT_DISK = this.mac_root_disk;
}
if (this.logger !== null) {
execution_env.NIX_INSTALLER_LOGGER = this.logger;
}
if (this.log_directives !== null) {
execution_env.NIX_INSTALLER_LOG_DIRECTIVES = this.log_directives;
}
// TODO: Error if the user uses these on MacOS
if (this.init !== null) {
if (process.env.RUNNER_OS === "macOS") {
throw new Error(
"`init` is not a valid option when `$RUNNER_OS` is `macOS`",
);
}
execution_env.NIX_INSTALLER_INIT = this.init;
}
if (this.start_daemon !== null) {
if (this.start_daemon) {
execution_env.NIX_INSTALLER_START_DAEMON = "true";
} else {
execution_env.NIX_INSTALLER_START_DAEMON = "false";
}
}
let extra_conf = "";
if (this.github_token !== null) {
extra_conf += `access-tokens = github.com=${this.github_token}`;
extra_conf += "\n";
}
if (this.trust_runner_user !== null) {
extra_conf += `trusted-users = root ${process.env.USER}`;
extra_conf += "\n";
}
if (this.flakehub) {
extra_conf += `netrc-file = ${await this.flakehub_login()}`;
extra_conf += "\n";
}
if (this.extra_conf !== null && this.extra_conf.length !== 0) {
extra_conf += this.extra_conf.join("\n");
extra_conf += "\n";
}
execution_env.NIX_INSTALLER_EXTRA_CONF = extra_conf;
if (process.env.ACT && !process.env.NOT_ACT) {
actions_core.info(
"Detected `$ACT` environment, assuming this is a https://github.com/nektos/act created container, set `NOT_ACT=true` to override this. This will change the setting of the `init` to be compatible with `act`",
);
execution_env.NIX_INSTALLER_INIT = "none";
}
return execution_env;
}
private async execute_install(binary_path: string): Promise<number> {
const execution_env = await this.executionEnvironment();
actions_core.info(
`Execution environment: ${JSON.stringify(execution_env, null, 4)}`,
);
const args = ["install"];
if (this.planner) {
args.push(this.planner);
} else {
args.push(get_default_planner());
}
if (this.extra_args) {
const extra_args = stringArgv(this.extra_args);
args.concat(extra_args);
}
const merged_env = {
...process.env, // To get $PATH, etc
...execution_env,
};
const spawned = spawn(`${binary_path}`, args, {
env: merged_env,
});
spawned.stdout.setEncoding("utf-8");
spawned.stdout.on("data", (data) => {
const trimmed = data.trimEnd();
if (trimmed.length >= 0) {
actions_core.info(trimmed);
}
});
spawned.stderr.setEncoding("utf-8");
spawned.stderr.on("data", (data) => {
const trimmed = data.trimEnd();
if (trimmed.length >= 0) {
actions_core.info(trimmed);
}
});
const exit_code: number = await new Promise((resolve, _reject) => {
spawned.on("close", resolve);
});
if (exit_code !== 0) {
throw new Error(`Non-zero exit code of \`${exit_code}\` detected`);
}
return exit_code;
}
async install(): Promise<void> {
const existing_install = await this.detect_existing();
if (existing_install) {
if (this.reinstall) {
// We need to uninstall, then reinstall
actions_core.info(
"Nix was already installed, `reinstall` is set, uninstalling for a reinstall",
);
await this.execute_uninstall();
} else {
// We're already installed, and not reinstalling, just set GITHUB_PATH and finish early
await this.set_github_path();
actions_core.info("Nix was already installed, using existing install");
return;
}
}
// Normal just doing of the install
const binary_path = await this.fetch_binary();
await this.execute_install(binary_path);
await this.set_github_path();
}
async set_github_path(): Promise<void> {
// Interim versions of the `nix-installer` crate may have already manipulated `$GITHUB_PATH`, as root even! Accessing that will be an error.
try {
const nix_var_nix_profile_path = "/nix/var/nix/profiles/default/bin";
const home_nix_profile_path = `${process.env.HOME}/.nix-profile/bin`;
actions_core.addPath(nix_var_nix_profile_path);
actions_core.addPath(home_nix_profile_path);
actions_core.info(
`Added \`${nix_var_nix_profile_path}\` and \`${home_nix_profile_path}\` to \`$GITHUB_PATH\``,
);
} catch (error) {
actions_core.info(
"Skipping setting $GITHUB_PATH in action, the `nix-installer` crate seems to have done this already. From `nix-installer` version 0.11.0 and up, this step is done in the action. Prior to 0.11.0, this was only done in the `nix-installer` binary.",
);
}
}
async flakehub_login(): Promise<string> {
const netrc_path = `${process.env["RUNNER_TEMP"]}/determinate-nix-installer-netrc`;
const jwt = await actions_core.getIDToken("api.flakehub.com");
await writeFile(
netrc_path,
[
`machine api.flakehub.com login flakehub password ${jwt}`,
`machine flakehub.com login flakehub password ${jwt}`,
].join("\n"),
);
actions_core.info("Logging in to FlakeHub.");
// the join followed by a match on ^... looks silly, but extra_config
// could contain multi-line values
if (this.extra_conf?.join("\n").match(/^netrc-file/m)) {
actions_core.warning(
"Logging in to FlakeHub conflicts with the Nix option `netrc-file`.",
);
}
return netrc_path;
}
async execute_uninstall(): Promise<number> {
const spawned = spawn(`/nix/nix-installer`, ["uninstall"], {
env: {
NIX_INSTALLER_NO_CONFIRM: "true",
...process.env, // To get $PATH, etc
},
});
spawned.stdout.setEncoding("utf-8");
spawned.stdout.on("data", (data) => {
const trimmed = data.trimEnd();
if (trimmed.length >= 0) {
actions_core.info(trimmed);
}
});
spawned.stderr.setEncoding("utf-8");
spawned.stderr.on("data", (data) => {
const trimmed = data.trimEnd();
if (trimmed.length >= 0) {
actions_core.info(trimmed);
}
});
const exit_code: number = await new Promise((resolve, _reject) => {
spawned.on("close", resolve);
});
if (exit_code !== 0) {
throw new Error(`Non-zero exit code of \`${exit_code}\` detected`);
}
return exit_code;
}
async detect_existing(): Promise<boolean> {
const receipt_path = "/nix/receipt.json";
try {
await access(receipt_path);
// There is a /nix/receipt.json
return true;
} catch {
// No /nix/receipt.json
return false;
}
}
private async fetch_binary(): Promise<string> {
if (!this.local_root) {
actions_core.info(`Fetching binary from ${this.nix_installer_url}`);
const response = await fetch(this.nix_installer_url);
if (!response.ok) {
throw new Error(
`Got a status of ${response.status} from \`${this.nix_installer_url}\`, expected a 200`,
);
}
const tempdir = await mkdtemp(join(tmpdir(), "nix-installer-"));
const tempfile = join(tempdir, `nix-installer-${this.platform}`);
if (!response.ok) {
throw new Error(`unexpected response ${response.statusText}`);
}
if (response.body !== null) {
const streamPipeline = promisify(pipeline);
await streamPipeline(response.body, fs.createWriteStream(tempfile));
actions_core.info(`Downloaded \`nix-installer\` to \`${tempfile}\``);
} else {
throw new Error("No response body recieved");
}
// Make executable
await chmod(tempfile, fs.constants.S_IXUSR | fs.constants.S_IXGRP);
return tempfile;
} else {
const local_path = join(
this.local_root,
`nix-installer-${this.platform}`,
);
actions_core.info(`Using binary ${local_path}`);
return local_path;
}
}
async report_overall(): Promise<void> {
if (this.diagnostic_endpoint == null) {
return;
}
try {
await fetch(this.diagnostic_endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"post-github-workflow-run-report": true,
correlation: this.correlation,
conclusion: await this.get_workflow_conclusion(),
}),
});
} catch (error) {
actions_core.debug(
`Error submitting post-run diagnostics report: ${error}`,
);
}
}
private async get_workflow_conclusion(): Promise<
undefined | "success" | "failure" | "cancelled" | "unavailable" | "no-jobs"
> {
if (this.github_token == null) {
return undefined;
}
try {
const octokit = github.getOctokit(this.github_token);
const jobs = await octokit.paginate(
octokit.rest.actions.listJobsForWorkflowRun,
{
owner: github.context.repo.owner,
repo: github.context.repo.repo,
run_id: github.context.runId,
},
);
actions_core.debug(`awaited jobs: ${jobs}`);
const job = jobs
.filter((candidate) => candidate.name === github.context.job)
.at(0);
if (job === undefined) {
return "no-jobs";
}
const outcomes = (job.steps || []).map((j) => j.conclusion || "unknown");
// Possible values: success, failure, cancelled, or skipped
// from: https://docs.github.com/en/actions/learn-github-actions/contexts
if (outcomes.includes("failure")) {
// Any failures fails the job
return "failure";
}
if (outcomes.includes("cancelled")) {
// Any cancellations cancels the job
return "cancelled";
}
// Assume success if no jobs failed or were canceled
return "success";
} catch (error) {
actions_core.debug(`Error determining final disposition: ${error}`);
return "unavailable";
}
}
}
type ExecuteEnvironment = {
// All env vars are strings, no fanciness here.
RUST_BACKTRACE?: string;
NIX_INSTALLER_MODIFY_PROFILE?: string;
NIX_INSTALLER_NIX_BUILD_GROUP_NAME?: string;
NIX_INSTALLER_NIX_BUILD_GROUP_ID?: string;
NIX_INSTALLER_NIX_BUILD_USER_PREFIX?: string;
NIX_INSTALLER_NIX_BUILD_USER_COUNT?: string;
NIX_INSTALLER_NIX_BUILD_USER_ID_BASE?: string;
NIX_INSTALLER_NIX_PACKAGE_URL?: string;
NIX_INSTALLER_PROXY?: string;
NIX_INSTALLER_SSL_CERT_FILE?: string;
NIX_INSTALLER_DIAGNOSTIC_ENDPOINT?: string;
NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION?: string;
NIX_INSTALLER_ENCRYPT?: string;
NIX_INSTALLER_CASE_SENSITIVE?: string;
NIX_INSTALLER_VOLUME_LABEL?: string;
NIX_INSTALLER_ROOT_DISK?: string;
NIX_INSTALLER_INIT?: string;
NIX_INSTALLER_START_DAEMON?: string;
NIX_INSTALLER_NO_CONFIRM?: string;
NIX_INSTALLER_EXTRA_CONF?: string;
NIX_INSTALLER_LOG_DIRECTIVES?: string;
NIX_INSTALLER_LOGGER?: string;
};
function get_nix_platform(): string {
const env_os = process.env.RUNNER_OS;
const env_arch = process.env.RUNNER_ARCH;
if (env_os === "macOS" && env_arch === "X64") {
return "x86_64-darwin";
} else if (env_os === "macOS" && env_arch === "ARM64") {
return "aarch64-darwin";
} else if (env_os === "Linux" && env_arch === "X64") {
return "x86_64-linux";
} else if (env_os === "Linux" && env_arch === "ARM64") {
return "aarch64-linux";
} else {
throw new Error(
`Unsupported \`RUNNER_OS\` (currently \`${env_os}\`) and \`RUNNER_ARCH\` (currently \`${env_arch}\`) combination`,
);
}
}
function get_default_planner(): string {
const env_os = process.env.RUNNER_OS;
if (env_os === "macOS") {
return "macos";
} else if (env_os === "Linux") {
return "linux";
} else {
throw new Error(`Unsupported \`RUNNER_OS\` (currently \`${env_os}\`)`);
}
}
function resolve_nix_installer_url(
platform: string,
correlation?: string,
): URL {
// Only one of these are allowed.
const nix_installer_branch = action_input_string_or_null(
"nix-installer-branch",
);
const nix_installer_pr = action_input_number_or_null("nix-installer-pr");
const nix_installer_revision = action_input_string_or_null(
"nix-installer-revision",
);
const nix_installer_tag = action_input_string_or_null("nix-installer-tag");
const nix_installer_url = action_input_string_or_null("nix-installer-url");
const url_suffix = `ci=github&correlation=${correlation}`;
let resolved_nix_installer_url = null;
let num_set = 0;
if (nix_installer_branch !== null) {
num_set += 1;
resolved_nix_installer_url = new URL(
`https://install.determinate.systems/nix/branch/${nix_installer_branch}/nix-installer-${platform}?${url_suffix}`,
);
} else if (nix_installer_pr !== null) {
num_set += 1;
resolved_nix_installer_url = new URL(
`https://install.determinate.systems/nix/pr/${nix_installer_pr}/nix-installer-${platform}?${url_suffix}`,
);
} else if (nix_installer_revision !== null) {
num_set += 1;
resolved_nix_installer_url = new URL(
`https://install.determinate.systems/nix/rev/${nix_installer_revision}/nix-installer-${platform}?${url_suffix}`,
);
} else if (nix_installer_tag !== null) {
num_set += 1;
resolved_nix_installer_url = new URL(
`https://install.determinate.systems/nix/tag/${nix_installer_tag}/nix-installer-${platform}?${url_suffix}`,
);
} else if (nix_installer_url !== null) {
num_set += 1;
resolved_nix_installer_url = new URL(nix_installer_url);
} else {
resolved_nix_installer_url = new URL(
`https://install.determinate.systems/nix/nix-installer-${platform}?${url_suffix}`,
);
}
if (num_set > 1) {
throw new Error(
`The following options are mututally exclusive, but ${num_set} were set: \`nix_installer_branch\`, \`nix_installer_pr\`, \`nix_installer_revision\`, \`nix_installer_tag\`, and \`nix_installer_url\``,
);
}
return resolved_nix_installer_url;
}
function action_input_string_or_null(name: string): string | null {
const value = actions_core.getInput(name);
if (value === "") {
return null;
} else {
return value;
}
}
function action_input_multiline_string_or_null(name: string): string[] | null {
const value = actions_core.getMultilineInput(name);
if (value.length === 0) {
return null;
} else {
return value;
}
}
function action_input_number_or_null(name: string): number | null {
const value = actions_core.getInput(name);
if (value === "") {
return null;
} else {
return Number(value);
}
}
function action_input_bool(name: string): boolean {
return actions_core.getBooleanInput(name);
}
async function main(): Promise<void> {
try {
if (!process.env["STATE_correlation"]) {
const correlation = `GH-${randomUUID()}`;
actions_core.saveState("correlation", correlation);
process.env["STATE_correlation"] = correlation;
}
const installer = new NixInstallerAction();
const isPost = !!process.env["STATE_isPost"];
if (!isPost) {
actions_core.saveState("isPost", "true");
await installer.install();
} else {
installer.report_overall();
}
} catch (error) {
if (error instanceof Error) actions_core.setFailed(error);
}
}
main();
+207
View File
@@ -0,0 +1,207 @@
import { mermaidify, makeMermaidReport } from "./mermaid.js";
import { DEvent, parseEvents } from "./events.js";
import { expect, test } from "vitest";
/* eslint-disable @typescript-eslint/no-non-null-assertion */
function generateEvents(count: number): DEvent[] {
const events: DEvent[] = [];
for (let i = 0; i < count; i++) {
events.push({
v: "1",
c: "BuiltPathResponseEventV1",
drv: `/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-${i}.drv`,
timing: {
startTime: new Date(i * 1000),
durationSeconds: i,
},
});
}
return events;
}
test("Empty event list returns no report", () => {
const report = makeMermaidReport([]);
expect(report).toBeUndefined();
});
test("Create a very large report doc and make sure it is small enough", () => {
const report = makeMermaidReport(generateEvents(2500))!;
// Assert the `.drv` suffix was pruned (1 reference = the NOTE at the end)
expect(report.match(/\.drv/g)!.length).equals(1);
// Assert the `/nix/store` prefix was pruned (1 reference = the NOTE at the end)
expect(report.match(/\/nix\/store\//g)!.length).equals(1);
// Assert that some events were pruned
expect(report.match(/dep-/g)!.length).lessThan(2500);
expect(report.match(/dep-/g)!.length).greaterThan(1500);
expect(report).toContain("suffix, and builds that took less than ");
expect(report.length).lessThan(50200);
expect(report.length).greaterThan(49000);
});
test("Create a medium large report doc and make sure it is small enough", () => {
const eventCount = 675;
const report = makeMermaidReport(generateEvents(eventCount))!;
// Assert the `.drv` suffix was pruned (1 reference = the NOTE at the end)
expect(report.match(/\.drv/g)!.length).equals(1);
// Assert the `/nix/store` prefix was pruned (1 reference = the NOTE at the end)
expect(report.match(/\/nix\/store\//g)!.length).equals(1);
// Assert that no lines were pruned
expect(report.match(/dep-/g)!.length).toStrictEqual(eventCount);
expect(report).toContain(
"suffixes have been removed to make the graph small enough to render",
);
expect(report.length).lessThan(50200);
expect(report.length).greaterThan(18000);
});
test("Create a small report doc and make sure it isn't pruned", () => {
const report = makeMermaidReport(generateEvents(100))!;
// Assert 100 events have the `.drv` suffix, ie: were not pruned
expect(report.match(/\.drv/g)!.length).equals(100);
// Assert 100 events have the `.drv` suffix, ie: were not pruned
expect(report.match(/\/nix\/store\//g)!.length).equals(100);
expect(report.length).lessThan(50000);
});
test("Generate a really big report and shrink it", () => {
const events = generateEvents(1000);
const originalLength = mermaidify(events, -1)!.length;
const limitedLengthZero = mermaidify(events, 0)!.length;
const limitedLengthOne = mermaidify(events, 1)!.length;
const limitedLengthTwo = mermaidify(events, 2)!.length;
expect(originalLength).greaterThan(limitedLengthZero);
expect(limitedLengthZero).greaterThan(limitedLengthOne);
expect(limitedLengthOne).greaterThan(limitedLengthTwo);
});
test("Generate a rough report of various length", () => {
const { events } = parseEvents([
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-0.drv",
outputs: ["/nix/store/qwlgz5da3pfb53gqpgdmazaj9jczrnly-dep-0"],
timing: {
startTime: "2025-04-11T14:38:02Z",
stopTime: "2025-04-11T14:38:05Z",
durationSeconds: 0,
},
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv",
outputs: ["/nix/store/qwlgz5da3pfb53gqpgdmazaj9jczrnly-dep-1"],
timing: {
startTime: "2025-04-11T14:38:02Z",
stopTime: "2025-04-11T14:38:05Z",
durationSeconds: 1,
},
},
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-2.drv",
outputs: ["/nix/store/qwlgz5da3pfb53gqpgdmazaj9jczrnly-dep-2"],
timing: {
startTime: "2025-04-11T14:38:02Z",
stopTime: "2025-04-11T14:38:05Z",
durationSeconds: 2,
},
},
{
v: "1",
c: "BuildFailureResponseEventV1",
drv: "/nix/store/ykvbksjqrza2zpj6nkbycrdfwgfdpr8g-hash-mismatch-md5-base16.drv",
timing: {
startTime: "2025-04-11T14:38:05Z",
stopTime: "2025-04-11T14:38:09Z",
durationSeconds: 4,
},
},
]);
expect(mermaidify(events, -1)).toStrictEqual(`\`\`\`mermaid
gantt
dateFormat X
axisFormat %Mm%Ss
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-0.drv (0s):d, 0, 0s
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-1.drv (1s):d, 0, 1s
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-2.drv (2s):d, 0, 2s
/nix/store/ykvbksjqrza2zpj6nkbycrdfwgfdpr8g-hash-mismatch-md5-base16.drv (4s):crit, 3, 4s
\`\`\``);
expect(mermaidify(events, 0)).toStrictEqual(`\`\`\`mermaid
gantt
dateFormat X
axisFormat %Mm%Ss
dep-0 (0s):d, 0, 0s
dep-1 (1s):d, 0, 1s
dep-2 (2s):d, 0, 2s
hash-mismatch-md5-base16 (4s):crit, 3, 4s
\`\`\``);
expect(mermaidify(events, 1)).toStrictEqual(`\`\`\`mermaid
gantt
dateFormat X
axisFormat %Mm%Ss
dep-1 (1s):d, 0, 1s
dep-2 (2s):d, 0, 2s
hash-mismatch-md5-base16 (4s):crit, 3, 4s
\`\`\``);
});
test("Generate a really big report and shrink it", () => {
const events = generateEvents(1000);
const originalLength = mermaidify(events, -1)!.length;
const limitedLengthZero = mermaidify(events, 0)!.length;
const limitedLengthOne = mermaidify(events, 1)!.length;
const limitedLengthTwo = mermaidify(events, 2)!.length;
expect(originalLength).greaterThan(limitedLengthZero);
expect(limitedLengthZero).greaterThan(limitedLengthOne);
expect(limitedLengthOne).greaterThan(limitedLengthTwo);
});
test("Really long builds get multi-unit timestamps", () => {
const { events } = parseEvents([
{
v: "1",
c: "BuiltPathResponseEventV1",
drv: "/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-0.drv",
outputs: ["/nix/store/qwlgz5da3pfb53gqpgdmazaj9jczrnly-dep-0"],
timing: {
startTime: "2025-04-11T14:38:02Z",
stopTime: "2026-05-14T13:32:01Z",
durationSeconds: 34383239,
},
},
]);
expect(mermaidify(events, -1)).toStrictEqual(`\`\`\`mermaid
gantt
dateFormat X
axisFormat %Mm%Ss
/nix/store/rz9hrpay90sjrid5hx3x8v606ji679xa-dep-0.drv (573053m59s):d, 0, 34383239s
\`\`\``);
});
+96
View File
@@ -0,0 +1,96 @@
import { DEvent } from "./events.js";
import { truncateDerivation } from "./util.js";
export function makeMermaidReport(events: DEvent[]): string | undefined {
// # 50k is the max: https://github.com/mermaid-js/mermaid/blob/c269dc822c528e1afbde34e18a1cad03d972d4fe/src/defaultConfig.js#L55
const maxLength = 49900;
let mermaid = "";
let pruneLevel = -2;
do {
pruneLevel += 1;
mermaid = mermaidify(events, pruneLevel) ?? "";
} while (mermaid.length > maxLength);
if (!mermaid) {
return undefined;
}
const lines = [
"<details open><summary><strong>Build timeline</strong> :hourglass_flowing_sand:</summary>",
"", // load bearing whitespace, deleting it breaks the details expander / markdown
mermaid,
"", // load bearing whitespace, deleting it breaks the details expander / markdown
];
if (pruneLevel === 0) {
lines.push("> [!NOTE]");
lines.push(
"> `/nix/store/[hash]` and the `.drv` suffixes have been removed to make the graph small enough to render.",
);
} else if (pruneLevel > 0) {
lines.push("> [!NOTE]");
lines.push(
`> \`/nix/store/[hash]\`, the \`.drv\` suffix, and builds that took less than ${formatDuration(pruneLevel)} have been removed to make the graph small enough to render.`,
);
}
lines.push(""); // load bearing whitespace, deleting it breaks the details expander / markdown
lines.push("</details>");
return lines.join("\n");
}
export function mermaidify(
allEvents: DEvent[],
pruneLevel: number,
): string | undefined {
const events = allEvents
.filter(
(event) =>
event.c === "BuiltPathResponseEventV1" ||
event.c === "BuildFailureResponseEventV1",
)
.sort(
(a, b) => a.timing.startTime.getTime() - b.timing.startTime.getTime(),
);
const firstEvent = events.at(0);
if (firstEvent === undefined) {
return undefined;
}
const zeroMoment = firstEvent.timing.startTime.getTime();
const lines = [
"```mermaid",
"gantt",
" dateFormat X",
" axisFormat %Mm%Ss",
];
for (const event of events) {
const duration = event.timing.durationSeconds;
if (duration < pruneLevel) {
continue;
}
const label = pruneLevel >= 0 ? truncateDerivation(event.drv) : event.drv;
const tag = event.c === "BuildFailureResponseEventV1" ? "crit" : "d";
const relativeStartTime =
(event.timing.startTime.getTime() - zeroMoment) / 1000;
lines.push(
`${label} (${formatDuration(duration)}):${tag}, ${relativeStartTime}, ${duration}s`,
);
}
lines.push("```");
return lines.join("\n");
}
function formatDuration(duration: number): string {
const durSeconds = duration % 60;
const durMinutes = (duration - durSeconds) / 60;
return `${durMinutes > 0 ? `${durMinutes}m` : ""}${durSeconds}s`;
}
+3
View File
@@ -0,0 +1,3 @@
export function truncateDerivation(drv: string): string {
return drv.replace(/^\/nix\/store\/[a-z0-9]+-/, "").replace(/\.drv$/, "");
}
+14 -14
View File
@@ -1,15 +1,15 @@
{
"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
},
"exclude": [
"node_modules",
"**/*.test.ts"
]
}
"compilerOptions": {
"target": "ES2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "Node16",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"resolveJsonModule": true,
"declaration": true
},
"exclude": ["node_modules", "dist"]
}
+15
View File
@@ -0,0 +1,15 @@
import { defineConfig } from "tsup";
import { name } from "./package.json";
export default defineConfig({
name,
entry: ["src/index.ts"],
format: ["esm"],
target: "node20",
bundle: true,
splitting: false,
clean: true,
dts: {
resolve: true,
},
});