-
Notifications
You must be signed in to change notification settings - Fork 2
145 lines (134 loc) · 6.6 KB
/
Copy pathgravityforms-update.yml
File metadata and controls
145 lines (134 loc) · 6.6 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
144
145
name: Gravityforms
on:
workflow_call:
inputs:
slug:
required: false
default: 'gravityforms'
type: string
outputs:
updated:
description: "If the update didnt exist and was built"
value: ${{ jobs.build.outputs.updated }}
version:
description: "The updated version"
value: ${{ jobs.build.outputs.version }}
secrets:
LICENSE_KEY:
required: true
jobs:
build:
name: Update plugin
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
updated: ${{ steps.update.outputs.updated }}
version: ${{ steps.update.outputs.version }}
steps:
- name: Checkout Repository
uses: actions/checkout@v5
- name: Setup PHP
uses: shivammathur/setup-php@v2
# gravityapi.com is a third-party endpoint and it does fall over. On
# 2026-08-25 all nine gravityapi-backed mirrors failed inside the same
# window (04:19:13-04:21:49 UTC), each hanging for exactly 60s - PHP's
# default_socket_timeout - before file_get_contents gave up and returned
# false. The endpoint was healthy again by morning.
#
# curl rather than file_get_contents so the call can be retried: the
# timers reset per attempt, so this waits out roughly seven minutes of
# vendor downtime instead of the single 60s shot we had before.
#
# No --fail: a 4xx body is more useful in the log than a bare exit code,
# and the validation step below turns it into a specific error. Transient
# HTTP statuses (408, 429, 5xx) are retried by curl regardless.
- name: Retrieve the license information
env:
LICENSE_KEY: ${{ secrets.LICENSE_KEY }}
run: |
if ! curl -sS \
--retry 5 --retry-delay 20 --retry-all-errors \
--connect-timeout 15 --max-time 60 \
--get \
--data-urlencode "op=get_plugin" \
--data-urlencode "slug=${{ inputs.slug }}" \
--data-urlencode "key=$LICENSE_KEY" \
"https://gravityapi.com/wp-content/plugins/gravitymanager/api.php" \
> /tmp/remote-response.txt
then
echo "::error title=Could not reach gravityapi.com::The licensing endpoint did not answer for '${{ inputs.slug }}' after 6 attempts over several minutes. This is a vendor outage, not a repository problem - re-run the job once the endpoint is back."
exit 1
fi
# Everything downstream runs the response through `fromJson()` in a
# workflow expression, which the Actions template engine evaluates rather
# than a shell, so a bad body does not fail where it is fetched. Before
# this step, a failed fetch became `REMOTE_RESPONSE: false`, which then
# surfaced two steps later as:
#
# Missing package/download_url input
#
# *after* the "Download and extract" step had already run `git rm -rf .`
# on the checkout. That reads as a packaging bug in this shared workflow
# rather than "the vendor had a bad minute". Fail here instead, where we
# can say what actually happened.
#
# `download_url_latest` is checked too, not just well-formedness: this API
# answers an invalid or expired licence with a perfectly good serialized
# array carrying the real `version_latest` and an *empty*
# `download_url_latest` (verified against the live endpoint with a bogus
# key). Without the check that reads as a healthy response right up until
# the checkout has already been wiped.
- name: Validate the update response
run: |
body=/tmp/remote-response.txt
fail() {
# Actions masks registered secrets, so the licence key in an echoed
# request is redacted. Still cap the excerpt - the endpoint returns
# an entire HTML error page when it is unhappy.
echo "::error title=Bad update response from gravityapi.com::$1 First 200 bytes of the response follow; see the step log for more."
echo "--- response excerpt ---"
head -c 200 "$body"
echo
echo "--- end (total $(wc -c < "$body") bytes) ---"
exit 1
}
[ -s "$body" ] || fail "The endpoint returned an empty body, so there is no version to compare against."
status=0
php -r '
$data = @unserialize(file_get_contents($argv[1]));
if (!is_array($data)) { exit(2); }
if (($data["version_latest"] ?? "") === "") { exit(3); }
if (($data["download_url_latest"] ?? "") === "") { exit(4); }
file_put_contents("/tmp/remote-response.json", json_encode($data));
' "$body" || status=$?
case "$status" in
0) ;;
2) fail "The endpoint returned a body that is not a PHP-serialized array - usually an error page or a maintenance notice rather than the licensing API." ;;
3) fail "The response unserializes but carries no \`version_latest\` for '${{ inputs.slug }}' - check the slug is one this API knows about." ;;
4) fail "The response carries a version but an empty \`download_url_latest\`, which is how this API reports an invalid or expired licence for '${{ inputs.slug }}'." ;;
*) fail "Could not read the response (php exited $status)." ;;
esac
echo "Update response OK - ${{ inputs.slug }} reports version $(jq -r .version_latest /tmp/remote-response.json)."
- name: Read remote response
run: |
{
echo 'REMOTE_RESPONSE<<EOF'
cat /tmp/remote-response.json
echo -e "\n"
echo 'EOF'
} >> "$GITHUB_ENV"
- name: Update repo
uses: generoi/github-action-update-plugins@master
id: update
with:
download_url: ${{ fromJson(env.REMOTE_RESPONSE).download_url_latest }}
version: ${{ fromJson(env.REMOTE_RESPONSE).version_latest }}
# change_log.txt ships with CRLF line endings, so strip the CR before
# matching. Without it `$2` on a bare `### 3.0.2.5` heading is
# "3.0.2.5\r" and never equals ver, leaving the release notes empty.
# Dated headings (`### 3.0.2 | 2026-08-05`) matched by accident because
# the CR landed on the date field instead — which is why only the
# x.y.z releases ever got a changelog and the x.y.z.w ones did not.
changelog_extract: |-
awk -v ver=${{ fromJson(env.REMOTE_RESPONSE).version_latest }} '{ sub(/\r$/, "") } /^### / { if (p) { exit }; if ($2 == ver) { p=1; next } } p && NF' change_log.txt 2>&1