#!/usr/bin/env bash # 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 . function get_output_file { local output_file action_file action_file="action.yml" [ ! -f "$action_file" ] && action_file="action.yaml" output_file=$(grep -E '^\s*main:\s*' "${TO_ACT}${action_file}" | awk '{print $2}') output_file=${output_file//\"/} echo ${output_file//\'/} } function script_exists { npm run | grep -q "^ $1" } ALL="$1" SHA="$2" DIR="$3" BUILD_FAILURE_DIR="$4" MISSING_ARTIFACT_DIR="$5" MAYBE_REPRODUCIBLE_DIR="$6" REPRODUCIBLE_DIR="$7" REPO_PRINTABLE="${ALL//\//_}_$SHA" # holds temporary print strings REPO=$(echo "$ALL" | awk -F'/' '{print $(1)}') TO_ACT=$(echo "$ALL" | awk -F'/' '{print $(2)}') REPO="$REPO/$TO_ACT" TO_ACT=$(echo "$ALL" | cut -d'/' -f3-) [[ -n "$TO_ACT" ]] && TO_ACT="$TO_ACT/" BUILD_DIR=$(mktemp -d) cd "$BUILD_DIR" echo "Cloning $REPO..." git clone "https://github.com/$REPO.git" repo > /dev/null 2>&1 cd repo echo "Checking out $SHA" git checkout "$SHA" > /dev/null 2>&1 # actions.yml refers to actions relatively, so if we parse # ../dist/foo/ as the action final build dir, we need to # refer to it relative to the curr dir of the script # this is one way DIST="$TO_ACT$(get_output_file)" # some actions just name an index.js in the root dir. # In cases they name a directory, we'll diff the full thing. [ "$(dirname "$DIST")" != "." ] && DIST="$(dirname "$DIST")" REFERENCE_DIST="$DIST.1" echo "Saving $DIST to $REFERENCE_DIST" mv "$DIST" "$REFERENCE_DIST" cd "$DIR" echo "Installing packages..." INSTALL=$(npm ci 2>&1) echo "Attempting to build..." TMP="owo what's the build command" # surely ONE of these will work... if COMM="release"; script_exists "$COMM"; then echo "Trying '$COMM'..." TMP=$(npm run "$COMM" 2>&1) elif COMM="package"; script_exists "$COMM"; then echo "Trying '$COMM'..." TMP=$(npm run "$COMM" 2>&1) elif COMM="bundle"; script_exists "$COMM"; then echo "Trying '$COMM'..." TMP=$(npm run "$COMM" 2>&1) elif COMM="build"; script_exists "$COMM"; then echo "Trying '$COMM'..." TMP=$(npm run "$COMM" 2>&1) fi # if the build fails, the developers may have failed to setup # the environment properly, or it uses deprecated features. # It may be that there is no build command at all! This needs # manual review. if [[ $? -ne 0 ]]; then echo "$ALL did not build." echo "$INSTALL" > "$BUILD_FAILURE_DIR/${REPO_PRINTABLE}.log" echo "$TMP" >> "$BUILD_FAILURE_DIR/${REPO_PRINTABLE}.log" exit 0 #don't kill outer script fi # return back to where we were cd "$BUILD_DIR" cd repo if [[ ! -d "$DIST" ]]; then # TODO: if the dist dir wasn't produced, then the commands # used were likely wrong echo "$ALL did not produce artifacts." echo "$INSTALL" >> "$MISSING_ARTIFACT_DIR/${REPO_PRINTABLE}.log" echo "$TMP" >> "$MISSING_ARTIFACT_DIR/${REPO_PRINTABLE}.log" exit 0 fi # diffoscope will output binary diffs if line endings are not # comparable. --force forces it to convert binary files too. find "$REFERENCE_DIST" -type f -exec dos2unix --force {} \; # TODO: solves path errors in containers when using global install mkdir -p "$HOME/.npm-global" npm config set prefix "$HOME/.npm-global" export PATH="$HOME/.npm-global/bin:$PATH" # diffoscope uses to compare pretty npm install -g js-beautify diffoscope "$DIST" "$REFERENCE_DIST" \ --exclude-directory-metadata=yes \ --html "$MAYBE_REPRODUCIBLE_DIR/${REPO_PRINTABLE}.html" if [[ ! -f "$MAYBE_REPRODUCIBLE_DIR/${REPO_PRINTABLE}.html" ]]; then touch "$REPRODUCIBLE_DIR/${REPO_PRINTABLE}.flag" exit 0 fi