;; kenku --- crawl and reproduce github actions ;; Copyright © 2026 bdunahu ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;; ;; ;; This file reads from standard in a list of repo identifiers and commits: ;; ;; 1fexd/gh-create-release-notes 0.0.18 ;; 1password/load-secrets-action 92467eb28f72e8255933372f1e0707c567ce2259 ;; 1password/load-secrets-action v3 ;; 2428392/gh-truncate-string-action b3ff790d21cf42af3ca7579146eedb93c8fb0757 ;; 2428392/gh-truncate-string-action v1.0.0 ;; 3ru/gpt-translate master ;; 8398a7/action-slack 77eaa4f1c608a7d68b38af4e3f739dcd8cba273e ;; ;; It only cares about the first two columns, but writes a third. What does it ;; write? It writes where it found a lockfile in the associated repo, if any. ;; I did this because I noticed some repos were putting the lockfiles in a sub- ;; directory with the action.yml. Repos can put it anywhere they want if they're ;; mean, but I will not be downloading the repo at this phase or spending my ;; tokens on a recursive find. ;; The detected types of lockfiles are for npm, pnpm, and yarn. ;; ;; Depending on what it finds, it filters the result to a different output file ;; automatically. Like the other files, since we're using the github REST API, ;; set your $TOKEN env variable. (define-module (src crawl-lockfiles) #:use-module ((src utils) #:prefix util:) #:use-module ((src config) #:prefix conf:) #:use-module ((src crawl-type-wrapper) #:prefix types:) #:use-module ((ice-9 rdelim)) #:export (npm-file crawl-lockfiles)) (define outdir (in-vicinity conf:cache-dir "lock-friend")) (define npm-file (in-vicinity outdir "npm.txt")) (define github-api-template "https://api.github.com/repos/~a/~a/contents/~a?ref=~a") (define lockfiles-to-outfile '(("package-lock.json" . "npm.txt") ("yarn.lock" . "alt-pm.txt") ("pnpm-lock.yaml" . "alt-pm.txt") ("pnpm-lock.yml" . "alt-pm.txt") ("" . "no-lock.txt"))) (define (search-for-lockfiles owner name rest sha) (define (search files) (let* ((file (car files)) (remain (cdr files)) (url (format #f github-api-template owner name file sha))) (if (util:url-exists? url) file (and (not (null? remain)) (search remain))))) (let* ((lockfiles (map car lockfiles-to-outfile)) (to-try (append lockfiles (map (lambda (f) (in-vicinity rest f)) lockfiles)))) (search to-try))) (define (filter-to-file line) (let* ((parts (string-split line char-set:whitespace)) (paths (car parts)) (sha (cadr parts)) (seg (string-split paths #\/)) (owner (car seg)) (name (cadr seg)) (rest (string-join (list-tail seg 2) "/")) (lock (search-for-lockfiles owner name rest sha)) (output (open-file (in-vicinity outdir (assoc-ref lockfiles-to-outfile lock)) "a"))) ;; stream output (format output "~a ~a ~a\n" paths sha lock) (close output))) (define (crawl-lockfiles) (util:mkdir-p outdir) (call-with-input-file types:node-file (lambda (port) (let loop () (let ((line (read-line port))) (unless (eof-object? line) (filter-to-file line) (loop)))))))