-
-
Notifications
You must be signed in to change notification settings - Fork 5
230 lines (207 loc) · 8.4 KB
/
Copy pathupdate-libs.yml
File metadata and controls
230 lines (207 loc) · 8.4 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
name: Update libs from CodeOnTheGo
on:
workflow_dispatch:
permissions:
contents: write
env:
PLUGINS_REMOTE_PATH: public_html/flags/plugins
jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Checkout plugin-examples
uses: actions/checkout@v4
with:
# PAT from a repo admin so the libs/ push bypasses the main ruleset.
# A fine-grained PAT must use the organization as its resource owner,
# not a personal account, or every push returns 403. The next step
# checks this. GITHUB_TOKEN is only a fallback to keep checkout
# working; it cannot bypass the ruleset, so the check rejects it.
token: ${{ secrets.ADMIN_PERSONAL_ACCESS_TOKEN || github.token }}
# The build below takes ~30 minutes. Without this guard, a token that
# cannot write to this repo throws all of that away at "Commit updated
# jars". Check the token first so the run fails in seconds instead.
- name: Verify the push token
env:
ADMIN_PAT: ${{ secrets.ADMIN_PERSONAL_ACCESS_TOKEN }}
GH_TOKEN: ${{ secrets.ADMIN_PERSONAL_ACCESS_TOKEN || github.token }}
run: |
org="${GITHUB_REPOSITORY%%/*}"
if [ -z "$ADMIN_PAT" ]; then
echo "::error::ADMIN_PERSONAL_ACCESS_TOKEN is not set. GITHUB_TOKEN cannot bypass the ${org} main ruleset, so the push would fail."
exit 1
fi
if ! repo=$(gh api "repos/${GITHUB_REPOSITORY}" 2>/dev/null); then
echo "::error::The token cannot see ${GITHUB_REPOSITORY}. A fine-grained PAT must use resource owner '${org}' (the organization). A token owned by a personal account cannot reach ${org} repositories."
exit 1
fi
who=$(gh api user --jq .login 2>/dev/null || echo '(unknown)')
push=$(printf '%s' "$repo" | jq -r '.permissions.push // false')
echo "Token identity: ${who}. Push permission: ${push}."
if [ "$push" != "true" ]; then
echo "::error::The token authenticates as '${who}' but cannot write to ${GITHUB_REPOSITORY}. Grant it 'Contents: Read and write' with resource owner '${org}'."
exit 1
fi
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-disabled: true
add-job-summary: 'never'
- name: Compute release tag
id: tag
env:
RUN_NUMBER: ${{ github.run_number }}
run: echo "name=build-$(date -u +%Y-%m-%d)-${RUN_NUMBER}" >> "$GITHUB_OUTPUT"
- name: Run update-libs script
run: ./scripts/update-libs.sh
- name: Commit updated jars
id: commit
run: |
sha=$(git -C .cache/CodeOnTheGo rev-parse --short HEAD)
git config user.name "ADFA"
git config user.email "dev-team@appdevforall.org"
git add libs/
if git diff --cached --quiet; then
echo "No changes to libs/ — nothing to commit."
else
git commit -m "chore: update libs from CodeOnTheGo@${sha}"
git push
fi
echo "codeonthego_sha=${sha}" >> "$GITHUB_OUTPUT"
echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Stage .cgp files with website filenames
run: |
mkdir -p deploy-staging
declare -A MAP=(
["apk-viewer"]="apk-analyzer.cgp"
["Beepy"]="beepy.cgp"
["bookshelf"]="bookshelf.cgp"
["keystore-generator"]="keystore-generator.cgp"
["markdown-preview"]="markdown-previewer.cgp"
["ndk-installer-plugin"]="ndk-installer.cgp"
["random-xkcd"]="random-xkcd.cgp"
["snippets"]="snippets.cgp"
["icons-repository"]="icons-repository.cgp"
["rainbow-on-the-go"]="rainbow-on-the-go.cgp"
["ai-literacy-course"]="ai-literacy-course.cgp"
["flutter-template"]="flutter-template.cgp"
["get-ai-models"]="get-ai-models.cgp"
["project-to-template"]="project-to-template.cgp"
)
for module in "${!MAP[@]}"; do
src=$(ls "${module}/build/plugin/"*.cgp 2>/dev/null | head -n1)
if [ -z "$src" ]; then
echo "ERROR: no .cgp found under ${module}/build/plugin/"
exit 1
fi
cp "$src" "deploy-staging/${MAP[$module]}"
echo "Staged $src -> deploy-staging/${MAP[$module]}"
done
ls -la deploy-staging/
- name: Upload .cgp artifacts for deploy job
uses: actions/upload-artifact@v4
with:
name: plugins-cgp
path: deploy-staging/*.cgp
retention-days: 7
if-no-files-found: error
- name: Publish release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.tag.outputs.name }}
target_commitish: ${{ steps.commit.outputs.head_sha }}
body: Built against CodeOnTheGo@${{ steps.commit.outputs.codeonthego_sha }}.
fail_on_unmatched_files: true
files: '*/build/plugin/*.cgp'
deploy:
needs: release
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Download .cgp artifacts
uses: actions/download-artifact@v4
with:
name: plugins-cgp
path: deploy-staging
- name: List staged files
run: ls -la deploy-staging/
- name: Set up SSH key
env:
GREENGEEKS_HOST: ${{ vars.GREENGEEKS_SSH_HOST }}
GREENGEEKS_KEY: ${{ secrets.GREENGEEKS_SSH_PRIVATE_KEY }}
GREENGEEKS_USER: ${{ vars.GREENGEEKS_SSH_USER }}
run: |
mkdir -p ~/.ssh
if [ -z "$GREENGEEKS_HOST" ]; then
echo "Error: GREENGEEKS_SSH_HOST variable is not set"
exit 1
fi
echo "$GREENGEEKS_KEY" > ~/.ssh/id_rsa
sed -i '$ { /^$/ d; }' ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
if ! grep -q "BEGIN.*PRIVATE KEY" ~/.ssh/id_rsa; then
echo "Error: SSH key does not appear to be in correct format"
exit 1
fi
cat > ~/.ssh/config <<EOF
Host *
IdentitiesOnly yes
PreferredAuthentications publickey
StrictHostKeyChecking no
UserKnownHostsFile ~/.ssh/known_hosts
PubkeyAuthentication yes
PasswordAuthentication no
Host $GREENGEEKS_HOST
User $GREENGEEKS_USER
IdentityFile ~/.ssh/id_rsa
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
ConnectTimeout 60
ServerAliveInterval 60
ServerAliveCountMax 10
EOF
chmod 600 ~/.ssh/config
unset SSH_AUTH_SOCK
unset SSH_AGENT_PID
ssh-keyscan -H "$GREENGEEKS_HOST" >> ~/.ssh/known_hosts 2>/dev/null
- name: Upload .cgp files via scp
env:
REMOTE: ${{ vars.GREENGEEKS_SSH_USER }}@${{ vars.GREENGEEKS_SSH_HOST }}
run: |
for f in deploy-staging/*.cgp; do
echo "Uploading $f -> $REMOTE:$PLUGINS_REMOTE_PATH/$(basename "$f")"
scp -o StrictHostKeyChecking=no "$f" "$REMOTE:$PLUGINS_REMOTE_PATH/"
done
- name: Verify remote MD5 checksums
env:
REMOTE: ${{ vars.GREENGEEKS_SSH_USER }}@${{ vars.GREENGEEKS_SSH_HOST }}
run: |
names=$(cd deploy-staging && ls *.cgp | tr '\n' ' ')
remote_sums=$(ssh "$REMOTE" "cd $PLUGINS_REMOTE_PATH && md5sum $names")
failures=0
while IFS= read -r line; do
remote_md5=$(echo "$line" | awk '{print $1}')
name=$(echo "$line" | awk '{print $2}')
local_md5=$(md5sum "deploy-staging/$name" | cut -d ' ' -f1)
if [ "$local_md5" = "$remote_md5" ]; then
echo "OK $name ($local_md5)"
else
echo "FAIL $name local=$local_md5 remote=$remote_md5"
failures=$((failures+1))
fi
done <<< "$remote_sums"
if [ $failures -gt 0 ]; then
echo "ERROR: $failures file(s) failed MD5 verification"
exit 1
fi
- name: Cleanup SSH key
if: always()
run: |
rm -f ~/.ssh/id_rsa ~/.ssh/known_hosts || true