diff --git a/.github/workflows/scripts.run-with-summary.yml b/.github/workflows/scripts.run-with-summary.yml new file mode 100644 index 0000000..b2d0245 --- /dev/null +++ b/.github/workflows/scripts.run-with-summary.yml @@ -0,0 +1,47 @@ +# Test the scripts. +name: Run with Summary +on: + pull_request: + branches: + - main + +# Settings for run-with-summary script. +env: + FILE: report-${{ github.run_id }}.md + SUMMARY: | + - Environment: https://pr${{ github.event.number }}.demo.site + - Pull Request: ${{github.event.pull_request.html_url }} + +
${{ github.event.pull_request.title }} + ${{ github.event.pull_request.body }} +
+ DEBUG: yes + PATH: ./src:./bin:./vendor/bin:/usr/local/bin:/usr/bin:/bin + +jobs: + + run-with-summary: + name: run-with-summary success + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: run-with-summary + env: + HEADING: "Running Tests" + SUCCESS: "Test Command Succeeded :white_check_mark:" + ERROR: "Test Command Failed! :x:" + run: | + run-with-summary ls -la >> $GITHUB_STEP_SUMMARY + + run-with-summary-fail: + name: run-with-summary failure + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: run-with-summary failure + env: + HEADING: "Confirming command failure" + SUCCESS: "Command Succeeded :white_check_mark:" + ERROR: "Command Failed, as expected :x:" + run: | + run-with-summary ping w3.org -c5 | tee -a $GITHUB_STEP_SUMMARY diff --git a/README.md b/README.md index af7193c..8e96223 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,85 @@ # goatscripts Bash to basics. -# Example +These scripts are things I've been using in different places over the years. + +Help yourself. + +## Run With Summary + +`run-with-summary ` + +Executes a command and prints a markdown summary. + +Useful for CI systems like GitHub Actions. + +## Examples + +```shell + run-with-summary ping w3.org -c5 +``` + +To customize the report header text, show extra info in the table, or print the summary in the command run, use these env vars. ```shell -run-with-summary ping google.com -c2 +SUCCESS="Deploy complete" \ +ERROR="Deploy failed" \ +DEBUG=1 \ +SUMMARY=1 \ + run-with-summary deploy.sh +``` + +To output the results of a command to GitHub Actions summary, add this step to your workflow: + +```yaml +- name: Deploy script + env: + SUCCESS: "Deploy complete" + ERROR: "Deploy failed" + SUMMARY: | + - Environment: https://pr${{ github.event.number }}.demo.site + - Pull Request: ${{github.event.pull_request.html_url }} + +
${{ github.event.pull_request.title }} + ${{ github.event.pull_request.body }} +
+ run: | + run-with-summary deploy.sh ``` -DEBUG=1 SUMMARY=1 ./src/run-with-summary ping google.com -c2 -PING google.com (142.250.81.238): 56 data bytes -64 bytes from 142.250.81.238: icmp_seq=0 ttl=119 time=10.933 ms -64 bytes from 142.250.81.238: icmp_seq=1 ttl=119 time=9.472 ms - ---- google.com ping statistics --- -2 packets transmitted, 2 packets received, 0.0% packet loss -round-trip min/avg/max/stddev = 9.472/10.203/10.933/0.730 ms -# Command executed + +
+Example Output + +# Command complete + +Any markdown at all can be put into the SUMMARY env var. + ``` -ping google.com -c2 +ping w3.org -c5 ``` ``` -PING google.com (142.250.81.238): 56 data bytes -64 bytes from 142.250.81.238: icmp_seq=0 ttl=119 time=10.933 ms -64 bytes from 142.250.81.238: icmp_seq=1 ttl=119 time=9.472 ms +PING w3.org (104.18.22.19): 56 data bytes +64 bytes from 104.18.22.19: icmp_seq=0 ttl=59 time=9.480 ms +64 bytes from 104.18.22.19: icmp_seq=1 ttl=59 time=13.510 ms +64 bytes from 104.18.22.19: icmp_seq=2 ttl=59 time=12.989 ms +64 bytes from 104.18.22.19: icmp_seq=3 ttl=59 time=15.017 ms +64 bytes from 104.18.22.19: icmp_seq=4 ttl=59 time=13.225 ms ---- google.com ping statistics --- -2 packets transmitted, 2 packets received, 0.0% packet loss -round-trip min/avg/max/stddev = 9.472/10.203/10.933/0.730 ms +--- w3.org ping statistics --- +5 packets transmitted, 5 packets received, 0.0% packet loss +round-trip min/avg/max/stddev = 9.480/12.844/15.017/1.825 ms ``` -| Command | `ping google.com -c2` +| Command | `ping w3.org -c5` |------------|----------------------- | Exit Code | `0` -| Start Time | 2025-10-02 21:10:48 EDT -| End Time | 2025-10-02 21:10:49 EDT -| Duration | 1s +| Start Time | 2025-10-03 07:24:40 EDT +| End Time | 2025-10-03 07:24:40 EDT +| Duration | 4s | User | jonpugh | Host | macbookpro.lan | Directory | /Users/jonpugh/Work/Operations/goatscripts -Markdown report saved to /tmp/summary.md \ No newline at end of file +Markdown report saved to /tmp/summary.md +
diff --git a/src/run-with-summary b/src/run-with-summary index c6f7686..2058cb5 100755 --- a/src/run-with-summary +++ b/src/run-with-summary @@ -1,61 +1,74 @@ -#!/bin/bash - -# Customize the success and error messages. -success_message=${SUCCESS:-"Command executed"} -error_message=${ERROR:-"Command failed"} - -# Print extra stuff like user and hostname in the summary. -debug=${DEBUG:-""} - -# Print the markdown summary after the command output. -echo_summary=${SUMMARY:-""} +#!/usr/bin/env bash usage() { cat <<'USAGE' -Usage: run-with-summary [options] -- +Usage: run-with-summary -Executes the given command, streams its output, and writes a Markdown summary to /tmp/summary.md. +Executes the given command, streams its output, and writes a Markdown summary to $FILE. Environment variables: - SUCCESS Custom success heading (default: "Command executed"). - ERROR Custom error heading (default: "Command failed"). + HEADING Custom text for the h1 tag. (default: "Running Command...") + SUMMARY Short text to display below the header. + SUCCESS Custom success message (default: "Command succeeded"). + ERROR Custom error message (default: "Command failed"). DEBUG If set (non-empty), include User/Host/Directory in the summary. - SUMMARY If set (non-empty), echo the Markdown summary to stdout after execution. + FILE Markdown report file (default: /tmp/summary.md Examples: - run-with-summary ls -la - SUCCESS="Deploy complete" SUMMARY=1 run-with-summary -- make deploy + run-with-summary scripts/deploy.sh + + HEADING="Deployment" \ + SUMMARY="Deploy script running as an example." \ + SUCCESS="Deploy successful! :rocket:" \ + ERROR="DEPLOY FAILED! :x:" \ + DEBUG=1 \ + FILE=reports/$(date).md \ + run-with-summary scripts/deploy.sh + USAGE } +set -e + +# Customize the success and error messages. +command="$@" +heading_message=${HEADING:-"Command executed"} +summary=${SUMMARY:-"Started $(date)"} +success_message=${SUCCESS:-"Command executed successfully."} +error_message=${ERROR:-"Command failed"} + +# Print extra stuff like user and hostname in the summary. +debug=${DEBUG:-""} + +# Print the markdown summary after the command output. +temp_report_file=${FILE:-"/tmp/summary.md"} + +if [ -z "$command" ]; then + usage + exit 1 +fi + # Format output into markdown report format_output() { local command="$1" - local output="$2" - local exit_code="$3" - local start_time="$4" - local end_time="$5" + local exit_code="$2" + local start_time="$3" + local end_time="$4" local duration=$((end_time - start_time)) + + local start_date=$(date -d "@$start_time" '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || date -r $start_time '+%Y-%m-%d %H:%M:%S %Z') + local end_date=$(date -d "@$end_time" '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || date -r $end_time '+%Y-%m-%d %H:%M:%S %Z') - local heading_message="$error_message" + local message="$error_message" if [ "$exit_code" -eq 0 ]; then - heading_message="$success_message" + message="$success_message" fi - echo "# ${heading_message}" - echo "\`\`\`" - echo "$command" - echo "\`\`\`" - echo - echo "\`\`\`" - echo "$output" - echo "\`\`\`" - echo echo "| Command | \`$command\`" echo "|------------|-----------------------" echo "| Exit Code | \`$exit_code\`" - echo "| Start Time | $(date -r $start_time '+%Y-%m-%d %H:%M:%S %Z')" - echo "| End Time | $(date -r $end_time '+%Y-%m-%d %H:%M:%S %Z')" + echo "| Start Time | $start_date" + echo "| End Time | $end_date" echo "| Duration | ${duration}s" if [[ -n $debug ]]; then @@ -63,42 +76,42 @@ format_output() { echo "| Host | $(hostname -f)" echo "| Directory | $(pwd)" fi + echo + echo $message } -# Get the command from arguments -command="$@" -# Secondary help guard: if exactly one argument and it is -h/--help, show usage and exit 0 -if [ "$command" = "-h" ] || [ "$command" = "--help" ]; then - usage - exit 0 -fi - -if [ -z "$command" ]; then - usage - exit 1 -fi # Record start time start_time=$(date '+%s') # Execute command and show output in real time while capturing it -echo "Executing: $command" +# Use a temporary file to store output +temp_output_file=$(mktemp) + +if [[ -n ${heading_message} ]]; then + echo "# ${heading_message}" +fi + +if [[ -n ${summary} ]]; then + echo "${summary}" +fi + +echo "\`\`\`" +echo "$command" +echo "\`\`\`" +echo +echo "\`\`\`" + set -o pipefail -output=$(eval "$command" 2>&1 | tee >(cat >&2)) -exit_code=$? +$command +exit_code=${PIPESTATUS[0]} +echo "\`\`\`" -# Record end time end_time=$(date '+%s') # Generate markdown report -formatted_output=$(format_output "$command" "$output" "$exit_code" "$start_time" "$end_time") -echo "$formatted_output" > /tmp/summary.md - -if [[ -n $echo_summary ]]; then - echo "$formatted_output" -fi -echo -echo "Markdown report saved to /tmp/summary.md" +format_output "$command" "$exit_code" "$start_time" "$end_time" -exit "$exit_code" \ No newline at end of file +# Exit same as command. +exit "$exit_code"