Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
336952b
Create scripts.yaml
jonpugh Oct 2, 2025
22e77a7
Update scripts.yaml
jonpugh Oct 3, 2025
504fd83
Merge branch 'main' into jonpugh-patch-1
jonpugh Oct 3, 2025
407b9fd
Merge branch 'jonpugh-patch-1' of github.com:jonpugh/goatscripts into…
jonpugh Oct 3, 2025
d794312
Format dates properly.
jonpugh Oct 3, 2025
58b6bb6
New attempt at realtime output.
jonpugh Oct 3, 2025
84a5c81
Fix script run.
jonpugh Oct 3, 2025
d703a31
Add FILE env var, better example.
jonpugh Oct 3, 2025
8f90195
Add FILE env var, better example.
jonpugh Oct 3, 2025
35b1b88
Better readme.
jonpugh Oct 3, 2025
492a968
Export to file and print to summary.
jonpugh Oct 3, 2025
ccaca9d
file?
jonpugh Oct 3, 2025
50eb572
Don't errr
jonpugh Oct 3, 2025
8bf9f6a
Error code capture not happening on github.
jonpugh Oct 3, 2025
3aeca69
Change url to ping in tests.
jonpugh Oct 3, 2025
361bd6f
Don't announce the command.
jonpugh Oct 3, 2025
ec50f56
Print summary even if failed.
jonpugh Oct 3, 2025
d56f1de
Fix summary saving.
jonpugh Oct 3, 2025
627d7aa
Use bash to catch exit and print to summary.
jonpugh Oct 3, 2025
b91f757
Make sure script can't fail.
jonpugh Oct 3, 2025
949610f
or
jonpugh Oct 3, 2025
05bdc22
Set +e so the script fail doesn't fail the step.
jonpugh Oct 3, 2025
16ca381
Add a non-failing job.
jonpugh Oct 3, 2025
e8d3b1e
Allow pipes
jonpugh Oct 3, 2025
ec3e424
Get a failure check working.
jonpugh Oct 3, 2025
d4e682f
Get a failure check working.
jonpugh Oct 3, 2025
515e389
Get a failure check working.
jonpugh Oct 3, 2025
83c17a7
Get a failure check working.
jonpugh Oct 3, 2025
1c5ad59
This one should pass.
jonpugh Oct 3, 2025
e9053c4
Fix messages and exits
jonpugh Oct 3, 2025
d83bd7b
Fix messages and exits
jonpugh Oct 3, 2025
608892e
Wrong variable.
jonpugh Oct 3, 2025
ac568a1
Use debug
jonpugh Oct 3, 2025
b64cdab
Name the github
jonpugh Oct 3, 2025
747e971
Renamed
jonpugh Oct 3, 2025
fbcd9ec
Proper emoji.
jonpugh Oct 3, 2025
547d17c
Simpler failure command.
jonpugh Oct 3, 2025
17eb221
Set path.
jonpugh Oct 3, 2025
23b5447
Name jobs.
jonpugh Oct 3, 2025
0aec0d6
Set default summary file.
jonpugh Oct 3, 2025
d9520b4
Long fail.
jonpugh Oct 3, 2025
c9d47e1
> output is not shown in realtime for non-interactive sessions
jonpugh Oct 3, 2025
a9a9005
> stdbuf: failed to run command ‘eval’: No such file or directory
jonpugh Oct 3, 2025
d4ba38f
Using stdbuf to force line buffering for non-interactive sessions
jonpugh Oct 3, 2025
64b9e29
Try this?
jonpugh Oct 3, 2025
c5cf150
try something else.
jonpugh Oct 3, 2025
4661679
back to using stdbuf
jonpugh Oct 3, 2025
2655b80
Try using stdbuf if it exists.
jonpugh Oct 3, 2025
f199db0
Try again.
jonpugh Oct 3, 2025
6b80c62
Try different.
jonpugh Oct 3, 2025
9fa130f
Move usage to the top.
jonpugh Oct 3, 2025
0716552
Comment out test.
jonpugh Oct 3, 2025
9d94f51
Put example in details.
jonpugh Oct 3, 2025
dac4e22
Rewrite. JUST render markdown. Users decide what to do with it.
jonpugh Oct 3, 2025
22a770c
Cleanup tests
jonpugh Oct 3, 2025
aabe123
try tee
jonpugh Oct 3, 2025
0948a48
try tee
jonpugh Oct 3, 2025
f0372d2
Put the github PR description in the summary.
jonpugh Oct 3, 2025
4268c1c
Add a long summary.
jonpugh Oct 4, 2025
73555cb
More
jonpugh Oct 4, 2025
58bad72
More
jonpugh Oct 4, 2025
d4901dd
More
jonpugh Oct 4, 2025
7fbf190
Only show heading if present.
jonpugh Oct 4, 2025
d7bdc47
Print link to demo site.
jonpugh Oct 4, 2025
4c93b8f
Add more summary.
jonpugh Oct 4, 2025
a9ae760
Wrong
jonpugh Oct 4, 2025
f2ebaa4
Markdown.
jonpugh Oct 4, 2025
4de34c6
Markdown.
jonpugh Oct 4, 2025
c9be0af
Markdown.
jonpugh Oct 4, 2025
5211a44
Fix readme.
jonpugh Oct 4, 2025
c7d62b2
Fix readme.
jonpugh Oct 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/scripts.run-with-summary.yml
Original file line number Diff line number Diff line change
@@ -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 }}

<details><summary>${{ github.event.pull_request.title }}</summary>
${{ github.event.pull_request.body }}
</details>
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
89 changes: 66 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 <args>`

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 }}

<details><summary>${{ github.event.pull_request.title }}</summary>
${{ github.event.pull_request.body }}
</details>
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

<details>
<summary>Example Output</summary>

# 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
Markdown report saved to /tmp/summary.md
</details>
133 changes: 73 additions & 60 deletions src/run-with-summary
Original file line number Diff line number Diff line change
@@ -1,104 +1,117 @@
#!/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] -- <command and args>
Usage: run-with-summary <command and args>

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
echo "| User | $(whoami) "
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"
# Exit same as command.
exit "$exit_code"