-
Notifications
You must be signed in to change notification settings - Fork 1
211 lines (179 loc) · 7.38 KB
/
ci-cd.yml
File metadata and controls
211 lines (179 loc) · 7.38 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
name: Regenerate NEAR RPC Client (auto PR, merge & release)
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *" # daily at midnight
permissions:
contents: write
pull-requests: write
jobs:
regenerate-merge-release:
runs-on: ubuntu-latest
steps:
# Avoid infinite loop
- name: Exit if triggered by GitHub Actions bot
if: github.actor == 'github-actions[bot]'
run: |
echo "Triggered by GitHub Actions bot; exiting to avoid loop."
exit 0
# Checkout repo
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: true
# Setup JDK
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 21
# Gradlew executable
- name: Grant execute permission for Gradlew
run: chmod +x ./gradlew
# Run Generator (safe)
- name: Run Generator (safe mode)
id: generator
run: |
set +e
./gradlew :generator:run --args="--openapi-url https://raw.githubusercontent.com/near/nearcore/master/chain/jsonrpc/openapi/openapi.json" --no-daemon
EXIT_CODE=$?
set -e
if [ $EXIT_CODE -ne 0 ]; then
echo "⚠️ OpenAPI generation failed. Skipping regeneration."
echo "pr_required=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Generator completed successfully."
echo "pr_required=true" >> "$GITHUB_OUTPUT"
# Build without tests
- name: Build project (without tests)
run: ./gradlew build -x test --stacktrace --no-daemon
# Prepare branch, commit regenerated sources
- name: Prepare branch, commit regenerated sources
id: commit
env:
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
run: |
set -euo pipefail
git config --local user.email "automation@github.com"
git config --local user.name "GitHub Actions Bot"
SHORT_SHA=${GITHUB_SHA:0:8}
BRANCH="regenerate-openapi-${GITHUB_RUN_NUMBER}-${SHORT_SHA}"
git checkout -b "$BRANCH"
git add .
if git diff --staged --quiet; then
echo "No changes to commit"
echo "pr_required=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "chore: regenerate client from OpenAPI"
git push https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git "$BRANCH"
echo "pr_required=true" >> "$GITHUB_OUTPUT"
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
# Auto-create and merge PR
- name: Auto-create and merge PR
if: steps.commit.outputs.pr_required == 'true'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.PAT_TOKEN }}
script: |
const branch = '${{ steps.commit.outputs.branch }}';
const title = `chore: regenerate client from OpenAPI (${branch})`;
const body = `This PR regenerates the NEAR RPC client and models from the latest OpenAPI spec.\n\nAutomatically merged after generation.`;
const pr = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
head: branch,
base: "main",
body
});
await github.rest.pulls.merge({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.data.number,
merge_method: "squash"
});
# Output when no changes
- name: Output when no changes
if: steps.commit.outputs.pr_required != 'true'
run: echo "No regenerated changes — nothing to create a PR for."
# Sync main after merge (force fetch tags + main)
- name: Sync main after merge
if: steps.commit.outputs.pr_required == 'true'
run: |
set -euo pipefail
echo "Waiting for GitHub to update merge state..."
# give GitHub a moment
sleep 10
# force fetch main and tags from remote to ensure runner sees latest
git fetch origin main --force
git fetch origin --tags --force
git checkout main
git reset --hard origin/main
echo "Main branch and tags synced successfully."
# Determine new tag (SemVer Patch) — robust: read remote tags, sort, and ensure uniqueness
- name: Determine new tag version
if: steps.commit.outputs.pr_required == 'true'
id: tag
run: |
set -euo pipefail
# Make sure we have up-to-date tags
git fetch origin --tags --force
# List remote tags that match semver vMAJOR.MINOR.PATCH
# Use ls-remote to be sure we check remote state
TAGS=$(git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
if [ -z "${TAGS:-}" ]; then
LAST_TAG="v1.0.0"
else
# pick highest semantic version (sort -V works on ubuntu)
LAST_TAG=$(echo "$TAGS" | sort -V | tail -n1)
fi
echo "Last tag detected: ${LAST_TAG}"
# Parse components safely
IFS='.' read -r MAJOR MINOR PATCH <<<"${LAST_TAG#v}"
MAJOR=${MAJOR:-1}
MINOR=${MINOR:-0}
PATCH=${PATCH:-0}
# increment patch
PATCH=$((PATCH+1))
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
# ensure uniqueness in remote (race protection) - bump patch until unique
while git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -qx "${NEW_TAG}"; do
PATCH=$((PATCH+1))
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
done
echo "Determined new tag: ${NEW_TAG}"
echo "new_tag=${NEW_TAG}" >> $GITHUB_OUTPUT
# Create and push tag
- name: Create and push tag
id: create_tag
if: steps.commit.outputs.pr_required == 'true'
env:
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
run: |
set -euo pipefail
NEW_TAG="${{ steps.tag.outputs.new_tag }}"
# final safety check: if tag already exists remotely, skip
if git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -qx "${NEW_TAG}"; then
echo "Tag ${NEW_TAG} already exists on remote. Skipping."
echo "tag_created=false" >> $GITHUB_OUTPUT
exit 0
fi
git tag -a "${NEW_TAG}" -m "Release ${NEW_TAG} (automated)"
git push "https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "refs/tags/${NEW_TAG}"
echo "tag_created=true" >> $GITHUB_OUTPUT
echo "Created tag ${NEW_TAG}"
# Create GitHub Release
- name: Create GitHub Release
if: steps.create_tag.outputs.tag_created == 'true'
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.tag.outputs.new_tag }}
name: "Release ${{ steps.tag.outputs.new_tag }}"
body: |
🚀 Automated release generated by workflow.
This release was created automatically after merging the regenerated client into main.
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}