-
Notifications
You must be signed in to change notification settings - Fork 11
143 lines (120 loc) · 4.62 KB
/
Copy pathstep-duration-regression.yml
File metadata and controls
143 lines (120 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
name: Step Duration Regression
# Fails CI if the action's setup or post step exceeds STEP_MAX_SECONDS.
# Catches regressions of the dangling-Http2Session class of bug that
# silently added ~30s per step.
on:
workflow_dispatch:
pull_request:
push:
branches: [main]
schedule:
- cron: "17 6 * * *"
env:
STEP_MAX_SECONDS: "5"
SETUP_STEP_NAME: "Setup Docker Builder under test"
jobs:
exercise-action:
name: Run build with setup-docker-builder
runs-on: blacksmith
steps:
- name: Checkout
uses: actions/checkout@v6
- name: ${{ env.SETUP_STEP_NAME }}
uses: ./
with:
buildx-version: v0.23.0
- name: Trivial build
run: |
cat > Dockerfile.test <<'EOF'
FROM alpine:3.20
RUN echo "step-duration-regression"
EOF
docker buildx build -f Dockerfile.test --load -t setup-docker-builder-regression:local .
validate-step-durations:
name: Validate step durations
needs: exercise-action
if: always()
runs-on: blacksmith
permissions:
actions: read
contents: read
steps:
- name: Assert setup and post steps stay under threshold
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.run_id }}
REPO: ${{ github.repository }}
MAX_SECONDS: ${{ env.STEP_MAX_SECONDS }}
SETUP_STEP_NAME: ${{ env.SETUP_STEP_NAME }}
TARGET_JOB_NAME: "Run build with setup-docker-builder"
run: |
set -euo pipefail
echo "Fetching steps for run ${RUN_ID} in ${REPO}..."
jobs_json=$(gh api \
-H "Accept: application/vnd.github+json" \
"repos/${REPO}/actions/runs/${RUN_ID}/jobs?per_page=100")
setup_name="${SETUP_STEP_NAME}"
post_name="Post ${SETUP_STEP_NAME}"
# Returns step duration in seconds, or "MISSING".
step_duration_seconds() {
local job="$1"
local step="$2"
local line
line=$(echo "$jobs_json" | jq -r \
--arg job "$job" --arg step "$step" '
.jobs[] | select(.name == $job) | .steps[] | select(.name == $step) |
"\(.started_at) \(.completed_at)"
')
local started completed
started=$(echo "$line" | awk '{print $1}')
completed=$(echo "$line" | awk '{print $2}')
if [[ -z "${started:-}" || -z "${completed:-}" \
|| "${started}" == "null" || "${completed}" == "null" ]]; then
echo "MISSING"
return
fi
local s c
s=$(date -u -d "$started" +%s)
c=$(date -u -d "$completed" +%s)
echo $(( c - s ))
}
echo ""
echo "=== ${TARGET_JOB_NAME} steps ==="
echo "$jobs_json" | jq -r --arg job "$TARGET_JOB_NAME" '
.jobs[] | select(.name == $job) | .steps[] |
" step=\"\(.name)\" started=\(.started_at) completed=\(.completed_at) conclusion=\(.conclusion)"
'
setup_duration=$(step_duration_seconds "$TARGET_JOB_NAME" "$setup_name")
post_duration=$(step_duration_seconds "$TARGET_JOB_NAME" "$post_name")
echo ""
echo "Setup step (\"${setup_name}\"): ${setup_duration}s"
echo "Post step (\"${post_name}\"): ${post_duration}s"
echo "Threshold: ${MAX_SECONDS}s"
{
echo "## Step Durations"
echo ""
echo "| Step | Duration | Threshold |"
echo "|---|---:|---:|"
echo "| Setup (\`${setup_name}\`) | **${setup_duration}s** | ${MAX_SECONDS}s |"
echo "| Post (\`${post_name}\`) | **${post_duration}s** | ${MAX_SECONDS}s |"
} >> "$GITHUB_STEP_SUMMARY"
fail=0
assert_under_threshold() {
local label="$1" value="$2"
if [[ "$value" == "MISSING" ]]; then
echo "::error::Could not find ${label} step in job \"${TARGET_JOB_NAME}\". Did the previous job fail before the step ran?"
fail=1
return
fi
if (( value > MAX_SECONDS )); then
echo "::error::${label} step took ${value}s (> ${MAX_SECONDS}s threshold). Check for dangling open handles (Http2Session, axios keep-alive, fs watcher) at the end of the action body."
fail=1
fi
}
assert_under_threshold "setup" "$setup_duration"
assert_under_threshold "post" "$post_duration"
if (( fail )); then
exit 1
fi
echo ""
echo "Both steps are within threshold."