-
Notifications
You must be signed in to change notification settings - Fork 111
359 lines (324 loc) · 15.5 KB
/
build-wheels.yml
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
name: 'Build wheels'
run-name: 'Build wheels (python-tags=${{ inputs.python-tags }}, platform-tag=${{ inputs.platform-tag }}, unoptimized=${{ inputs.unoptimized }}, include-debug-info-for-macos=${{ inputs.include-debug-info-for-macos }}, run_tests=${{ inputs.run_tests }}, use-server-rc=${{ inputs.use-server-rc }}, server-tag=${{ inputs.server-tag }})'
# Build wheels on all (or select) Python versions supported by the Python client for a specific platform
on:
workflow_dispatch:
inputs:
# These are the usual cases for building wheels:
#
# 1. One wheel for *one* supported Python version. This is for running specialized tests that only need one Python version
# like valgrind or a failing QE test. And usually, we only need one wheel for debugging purposes.
# 2. Wheels for *all* supported Python versions for *one* supported platform. This is useful for testing workflow changes for a
# single OS or CPU architecture (e.g testing that changes to debugging modes work on all Python versions)
# 3. Wheels for *all* supported Python versions and *all* supported platforms. This is for building wheels for different
# CI/CD stages (e.g dev, stage, or master). We can also test debugging modes for all platforms that support them
#
# We're able to combine case 1 and 2 into one workflow by creating an input that takes in a JSON list of strings (Python tags)
# to build wheels for. Actual list inputs aren't supported yet, so it's actually a JSON list encoded as a string.
#
# However, it's harder to combine this workflow (case 1 + 2) with case 3, because matrix outputs don't exist yet
# in Github Actions. So all jobs in the cibuildwheel job would have to pass for a self hosted job to run.
# We want each platform to be tested independently of each other,
# so there is a wrapper workflow that has a list of platforms to test and reuses this workflow for each platform.
# If one platform fails, it will not affect the building and testing of another platform (we disable fail fast mode)
python-tags:
type: string
description: Valid JSON list of Python tags to build the client for
required: false
default: '["cp38", "cp39", "cp310", "cp311", "cp312"]'
platform-tag:
description: Platform to build the client for.
type: choice
required: true
options:
- manylinux_x86_64
- manylinux_aarch64
- macosx_x86_64
- macosx_arm64
- win_amd64
# Makes debugging via gh cli easier.
default: manylinux_x86_64
unoptimized:
description: 'macOS or Linux: Apply -O0 flag?'
# Windows supports a different flag to disable optimizations, but we haven't added support for it yet
type: boolean
required: false
default: false
include-debug-info-for-macos:
description: 'macOS: Build wheels for debugging?'
type: boolean
required: false
default: false
run_tests:
description: 'Run Aerospike server and run tests using built wheels?'
type: boolean
required: false
default: false
use-server-rc:
type: boolean
required: true
default: false
description: 'Test against server release candidate?'
server-tag:
required: true
default: 'latest'
description: 'Server docker image tag'
workflow_call:
inputs:
# See workflow call hack in update-version.yml
is_workflow_call:
type: boolean
default: true
required: false
python-tags:
type: string
required: false
default: '["cp38", "cp39", "cp310", "cp311", "cp312"]'
platform-tag:
type: string
required: true
# Only used in workflow_call event
sha-to-build-and-test:
type: string
required: true
unoptimized:
type: boolean
required: false
default: false
include-debug-info-for-macos:
type: boolean
required: false
default: false
run_tests:
type: boolean
required: false
default: false
use-server-rc:
required: false
type: boolean
default: false
description: 'Test against server release candidate?'
server-tag:
required: false
type: string
default: 'latest'
description: 'Server docker image tag'
secrets:
# Just make all the secrets required to make things simpler...
DOCKER_HUB_BOT_USERNAME:
required: true
DOCKER_HUB_BOT_PW:
required: true
MAC_M1_SELF_HOSTED_RUNNER_PW:
required: true
env:
COMMIT_SHA_TO_BUILD_AND_TEST: ${{ inputs.is_workflow_call == true && inputs.sha-to-build-and-test || github.sha }}
# Note that environment variables in Github are all strings
# Github mac m1 and windows runners don't support Docker / nested virtualization
# so we need to use self-hosted runners to test wheels for these platforms
RUN_INTEGRATION_TESTS_IN_CIBW: ${{ inputs.run_tests && (startsWith(inputs.platform-tag, 'manylinux') || inputs.platform-tag == 'macosx_x86_64') }}
jobs:
# Maps don't exist in Github Actions, so we have to store the map using a script and fetch it in a job
# This uses up more billing minutes (rounded up to 1 minute for each job run),
# but this should be ok based on the minutes usage data for the aerospike organization
get-runner-os:
outputs:
runner-os: ${{ steps.get-runner-os.outputs.runner_os }}
runs-on: ubuntu-22.04
steps:
- id: get-runner-os
# Single source of truth for which runner OS to use for each platform tag
run: |
declare -A hashmap
hashmap[manylinux_x86_64]="ubuntu-22.04"
hashmap[manylinux_aarch64]="aerospike_arm_runners_2"
hashmap[macosx_x86_64]="macos-12-large"
hashmap[macosx_arm64]="macos-14"
hashmap[win_amd64]="windows-2022"
echo runner_os=${hashmap[${{ inputs.platform-tag }}]} >> $GITHUB_OUTPUT
# Bash >= 4 supports hashmaps
shell: bash
cibuildwheel:
needs: get-runner-os
strategy:
matrix:
python-tag: ${{ fromJSON(inputs.python-tags) }}
fail-fast: false
runs-on: ${{ needs.get-runner-os.outputs.runner-os }}
env:
BUILD_IDENTIFIER: "${{ matrix.python-tag }}-${{ inputs.platform-tag }}"
MACOS_OPENSSL_VERSION: 3
steps:
- name: Create status check message
run: echo STATUS_CHECK_MESSAGE="cibuildwheel (${{ env.BUILD_IDENTIFIER }})" >> $GITHUB_ENV
shell: bash
- name: Show job status for commit
uses: myrotvorets/[email protected]
if: ${{ github.event_name != 'push' && github.event_name != 'pull_request' }}
with:
sha: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
context: ${{ env.STATUS_CHECK_MESSAGE }}
- uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
# We need the last tag before the ref, so we can relabel the version if needed
fetch-depth: 0
- name: 'macOS arm64: Install experimental Python 3.8 macOS arm64 build'
# By default, cibuildwheel installs and uses Python 3.8 x86_64 to cross compile macOS arm64 wheels
# There is a bug that builds macOS x86_64 wheels instead, so we install this Python 3.8 native ARM build to ensure
# the wheel is compiled for macOS arm64
# https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64
if: ${{ matrix.python-tag == 'cp38' && inputs.platform-tag == 'macosx_arm64' }}
run: |
curl -o /tmp/Python38.pkg https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg
sudo installer -pkg /tmp/Python38.pkg -target /
sh "/Applications/Python 3.8/Install Certificates.command"
- name: 'Windows: Add msbuild to PATH'
if: ${{ inputs.platform-tag == 'win_amd64' }}
uses: microsoft/[email protected]
- name: 'Windows: Install C client deps'
if: ${{ inputs.platform-tag == 'win_amd64' }}
run: nuget restore
working-directory: aerospike-client-c/vs
- name: 'macOS x86: Setup Docker using colima for testing'
if: ${{ env.RUN_INTEGRATION_TESTS_IN_CIBW == 'true' && inputs.platform-tag == 'macosx_x86_64' }}
uses: ./.github/actions/setup-docker-on-macos
- name: 'macOS x86: run Aerospike server in Docker container and connect via localhost'
if: ${{ env.RUN_INTEGRATION_TESTS_IN_CIBW == 'true' && inputs.platform-tag == 'macosx_x86_64' }}
uses: ./.github/actions/run-ee-server
with:
use-server-rc: ${{ inputs.use-server-rc }}
server-tag: ${{ inputs.server-tag }}
docker-hub-username: ${{ secrets.DOCKER_HUB_BOT_USERNAME }}
docker-hub-password: ${{ secrets.DOCKER_HUB_BOT_PW }}
# TODO: combine this composite action and the above into one
- name: "Linux: run Aerospike server in Docker container and configure config.conf to connect to the server container's Docker IP address"
if: ${{ env.RUN_INTEGRATION_TESTS_IN_CIBW == 'true' && startsWith(inputs.platform-tag, 'manylinux') }}
uses: ./.github/actions/run-ee-server-for-ext-container
with:
use-server-rc: ${{ inputs.use-server-rc }}
server-tag: ${{ inputs.server-tag }}
docker-hub-username: ${{ secrets.DOCKER_HUB_BOT_USERNAME }}
docker-hub-password: ${{ secrets.DOCKER_HUB_BOT_PW }}
- name: If not running tests against server, only run basic import test
if: ${{ env.RUN_INTEGRATION_TESTS_IN_CIBW == 'false' }}
# Use double quotes otherwise Windows will throw this error in cibuildwheel
# 'import
# ^
# SyntaxError: EOL while scanning string literal
run: echo "TEST_COMMAND=python -c \"import aerospike\"" >> $GITHUB_ENV
shell: bash
- name: Otherwise, enable integration tests
if: ${{ env.RUN_INTEGRATION_TESTS_IN_CIBW == 'true' }}
run: echo "TEST_COMMAND=cd {project}/test/ && pip install -r requirements.txt && python -m pytest new_tests/" >> $GITHUB_ENV
shell: bash
- name: Set unoptimize flag
if: ${{ inputs.unoptimized && (startsWith(inputs.platform-tag, 'manylinux') || startsWith(inputs.platform-tag, 'macosx')) }}
run: echo "UNOPTIMIZED=1" >> $GITHUB_ENV
- name: Set include dsym flag
if: ${{ inputs.include-debug-info-for-macos && startsWith(inputs.platform-tag, 'macosx') }}
run: echo "INCLUDE_DSYM=1" >> $GITHUB_ENV
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build wheel
uses: pypa/[email protected]
env:
CIBW_ENVIRONMENT_PASS_LINUX: ${{ inputs.unoptimized && 'UNOPTIMIZED' || '' }}
CIBW_ENVIRONMENT_MACOS: SSL_LIB_PATH="$(brew --prefix openssl@${{ env.MACOS_OPENSSL_VERSION }})/lib/" CPATH="$(brew --prefix openssl@${{ env.MACOS_OPENSSL_VERSION }})/include/" STATIC_SSL=1
CIBW_BUILD: ${{ env.BUILD_IDENTIFIER }}
CIBW_BUILD_FRONTEND: build
CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/aerospike/manylinux2014_x86_64:CLIENT-2217-openssl3-manylinux
CIBW_BEFORE_ALL_LINUX: >
yum install python-setuptools -y
# delvewheel is not enabled by default but we do need to repair the wheel
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path ./aerospike-client-c/vs/x64/Release -w {dest_dir} {wheel}"
CIBW_TEST_COMMAND: ${{ env.TEST_COMMAND }}
- name: Upload wheels to GitHub
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
path: ./wheelhouse/*.whl
name: ${{ env.BUILD_IDENTIFIER }}.build
- name: Set final commit status
uses: myrotvorets/[email protected]
if: ${{ always() && github.event_name != 'push' && github.event_name != 'pull_request' }}
with:
sha: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
status: ${{ job.status }}
context: ${{ env.STATUS_CHECK_MESSAGE }}
test-self-hosted:
needs: cibuildwheel
# There's a top-level env variable for this but we can't use it here, unfortunately
if: ${{ inputs.run_tests && (inputs.platform-tag == 'macosx_arm64' || inputs.platform-tag == 'win_amd64') }}
strategy:
fail-fast: false
matrix:
python-tag: ${{ fromJSON(inputs.python-tags) }}
runs-on: ${{ inputs.platform-tag == 'macosx_arm64' && fromJSON('["self-hosted", "macOS", "ARM64"]') || fromJSON('["self-hosted", "Windows", "X64"]') }}
env:
BUILD_IDENTIFIER: "${{ matrix.python-tag }}-${{ inputs.platform-tag }}"
steps:
- name: Create status check message
run: echo STATUS_CHECK_MESSAGE="Test on self hosted (${{ env.BUILD_IDENTIFIER }})" >> $GITHUB_ENV
shell: bash
- name: Show job status for commit
uses: myrotvorets/[email protected]
if: ${{ github.event_name != 'push' && github.event_name != 'pull_request' }}
with:
sha: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
context: ${{ env.STATUS_CHECK_MESSAGE }}
- uses: actions/checkout@v4
with:
ref: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
# Need to be able to save Docker Hub credentials to keychain
- if: ${{ inputs.platform-tag == 'macosx_arm64' && inputs.use-server-rc }}
run: security unlock-keychain -p ${{ secrets.MAC_M1_SELF_HOSTED_RUNNER_PW }}
- uses: ./.github/actions/run-ee-server
with:
use-server-rc: ${{ inputs.use-server-rc }}
server-tag: ${{ inputs.server-tag }}
docker-hub-username: ${{ secrets.DOCKER_HUB_BOT_USERNAME }}
docker-hub-password: ${{ secrets.DOCKER_HUB_BOT_PW }}
- name: Download wheel
uses: actions/download-artifact@v4
with:
name: ${{ env.BUILD_IDENTIFIER }}.build
- name: Convert Python tag to Python version
# Don't use sed because we want this command to work on both mac and windows
# The command used in GNU sed is different than in macOS sed
run: |
PYTHON_TAG=${{ matrix.python-tag }}
PYTHON_VERSION="${PYTHON_TAG/cp/}"
echo PYTHON_VERSION="${PYTHON_VERSION/3/3.}" >> $GITHUB_ENV
shell: bash
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install wheel
run: python3 -m pip install aerospike --force-reinstall --no-index --find-links=./
shell: bash
- name: Connect to Docker container on remote machine with Docker daemon
if: ${{ inputs.platform-tag == 'win_amd64' }}
# DOCKER_HOST contains the IP address of the remote machine
run: |
$env:DOCKER_HOST_IP = $env:DOCKER_HOST | foreach {$_.replace("tcp://","")} | foreach {$_.replace(":2375", "")}
crudini --set config.conf enterprise-edition hosts ${env:DOCKER_HOST_IP}:3000
working-directory: test
- run: python3 -m pip install pytest -c requirements.txt
working-directory: test
shell: bash
- run: python3 -m pytest new_tests/
working-directory: test
shell: bash
- name: Show job status for commit
if: ${{ always() && github.event_name != 'push' && github.event_name != 'pull_request' }}
uses: myrotvorets/[email protected]
with:
sha: ${{ env.COMMIT_SHA_TO_BUILD_AND_TEST }}
status: ${{ job.status }}
context: ${{ env.STATUS_CHECK_MESSAGE }}