Skip to content

Commit edd4def

Browse files
feat: adds python SDK (#99)
Co-authored-by: Vicente Pinto <[email protected]>
1 parent 701a5b2 commit edd4def

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4379
-10
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: Generate SDK
2+
description: "Generates the Python SDK"
3+
inputs:
4+
python-version:
5+
description: "Python version to install"
6+
required: true
7+
runs:
8+
using: "composite"
9+
steps:
10+
- name: Download OAS
11+
shell: bash
12+
run: make download-oas
13+
- name: Generate SDK
14+
shell: bash
15+
run: make generate-sdk LANGUAGE=python

.github/workflows/ci.yaml

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ env:
77
JAVA_VERSION: "11"
88

99
jobs:
10-
main:
11-
name: CI
10+
main-go:
11+
name: CI [Go]
1212
strategy:
1313
matrix:
1414
os: [ubuntu-latest, macos-latest]
@@ -32,7 +32,7 @@ jobs:
3232
with:
3333
go-version: ${{ env.GO_VERSION_BUILD }}
3434
- name: Generate SDK
35-
uses: ./.github/actions/generate-sdk
35+
uses: ./.github/actions/generate-sdk/go
3636
- name: Install Go ${{ matrix.go-version }}
3737
uses: actions/setup-go@v5
3838
with:
@@ -44,3 +44,43 @@ jobs:
4444
- name: Test
4545
working-directory: ./sdk-repo-updated
4646
run: make test skip-non-generated-files=true
47+
main-python:
48+
name: CI [Python]
49+
strategy:
50+
matrix:
51+
os: [ubuntu-latest, macos-latest]
52+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
53+
runs-on: ${{ matrix.os }}
54+
steps:
55+
- name: Install SSH Key
56+
uses: shimataro/ssh-key-action@v2
57+
with:
58+
key: ${{ secrets.SSH_PRIVATE_KEY }}
59+
known_hosts: ${{ vars.SSH_KNOWN_HOSTS }}
60+
- name: Install Java
61+
uses: actions/setup-java@v4
62+
with:
63+
distribution: "temurin"
64+
java-version: ${{ env.JAVA_VERSION }}
65+
- name: Checkout
66+
uses: actions/checkout@v4
67+
- name: Build
68+
uses: ./.github/actions/build
69+
with:
70+
go-version: ${{ env.GO_VERSION_BUILD }}
71+
- name: Generate SDK
72+
uses: ./.github/actions/generate-sdk/python
73+
- name: Install Python ${{ matrix.python-version }}
74+
uses: actions/setup-python@v5
75+
with:
76+
python-version: ${{ matrix.python-version }}
77+
- name: Install core
78+
run: |
79+
git clone https://github.com/stackitcloud/stackit-sdk-python-core.git core
80+
cd core;make install-dev;
81+
- name: Lint
82+
working-directory: ./sdk-repo-updated
83+
run: make lint
84+
- name: Test
85+
working-directory: ./sdk-repo-updated
86+
run: make test

.github/workflows/sdk-pr.yaml

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ env:
1111
JAVA_VERSION: '11'
1212

1313
jobs:
14-
main:
14+
main-go:
1515
name: Update SDK Repo
1616
runs-on: ubuntu-latest
1717
steps:
@@ -32,10 +32,38 @@ jobs:
3232
with:
3333
go-version: ${{ env.GO_VERSION }}
3434
- name: Generate SDK
35-
uses: ./.github/actions/generate-sdk
35+
uses: ./.github/actions/generate-sdk/go
3636
- name: Push SDK
3737
env:
3838
GH_REPO: 'stackitcloud/stackit-sdk-go'
3939
GH_TOKEN: ${{ secrets.SDK_PR_TOKEN }}
4040
run: |
41-
scripts/sdk-create-pr.sh "generator-bot-${{ github.run_id }}" "Generated from GitHub run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
41+
scripts/sdk-create-pr.sh "generator-bot-${{ github.run_id }}" "Generated from GitHub run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
42+
main-python:
43+
name: Update SDK Repo
44+
runs-on: ubuntu-latest
45+
steps:
46+
- name: Install SSH Key
47+
uses: shimataro/ssh-key-action@v2
48+
with:
49+
key: ${{ secrets.SSH_PRIVATE_KEY }}
50+
known_hosts: ${{ vars.SSH_KNOWN_HOSTS }}
51+
- name: Install Java
52+
uses: actions/setup-java@v4
53+
with:
54+
distribution: 'temurin'
55+
java-version: ${{ env.JAVA_VERSION }}
56+
- name: Checkout
57+
uses: actions/checkout@v4
58+
- name: Build
59+
uses: ./.github/actions/build
60+
with:
61+
go-version: ${{ env.GO_VERSION }}
62+
- name: Generate SDK
63+
uses: ./.github/actions/generate-sdk/python
64+
- name: Push SDK
65+
env:
66+
GH_REPO: 'stackitcloud/stackit-sdk-python'
67+
GH_TOKEN: ${{ secrets.SDK_PR_TOKEN }}
68+
run: |
69+
scripts/sdk-create-pr.sh "generator-bot-${{ github.run_id }}" "Generated from GitHub run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" "[email protected]:stackitcloud/stackit-sdk-python.git" "python"

scripts/generate-sdk/.openapi-generator-ignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,11 @@ git_push.sh
55
README.md
66
response.go
77
api/openapi.yaml
8-
.openapi-generator/*
8+
.openapi-generator/*
9+
.gitlab-ci.yml
10+
setup.cfg
11+
setup.py
12+
test-requirements.txt
13+
requirements.txt
14+
tox.ini
15+
*/.github/*

scripts/generate-sdk/generate-sdk.sh

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ ROOT_DIR=$(git rev-parse --show-toplevel)
1515
GENERATOR_PATH="${ROOT_DIR}/scripts/bin"
1616
LANGUAGE_GENERATORS_FOLDER_PATH="${ROOT_DIR}/scripts/generate-sdk/languages/"
1717
# Renovate: datasource=github-tags depName=OpenAPITools/openapi-generator versioning=semver
18-
GENERATOR_VERSION="v6.6.0"
19-
GENERATOR_VERSION_NUMBER="${GENERATOR_VERSION:1}"
2018

2119
# Check parameters and set defaults if not provided
2220
if [[ -z ${GIT_HOST} ]]; then
@@ -46,6 +44,21 @@ if [ ! -d ${ROOT_DIR}/oas ]; then
4644
echo "\"oas\" folder not found in root. Please add it manually or run \"make download-oas\"."
4745
exit 1
4846
fi
47+
# Choose generator version depending on the language
48+
# Renovate: datasource=github-tags depName=OpenAPITools/openapi-generator versioning=semver
49+
case "${LANGUAGE}" in
50+
go)
51+
GENERATOR_VERSION="v6.6.0" # There are issues with GO SDK generation in version v7
52+
;;
53+
python)
54+
GENERATOR_VERSION="v7.7.0"
55+
;;
56+
*)
57+
echo "SDK language not supported."
58+
exit 1
59+
;;
60+
esac
61+
GENERATOR_VERSION_NUMBER="${GENERATOR_VERSION:1}"
4962

5063
# Download OpenAPI generator if not already downloaded
5164
jar_path="${GENERATOR_PATH}/openapi-generator-cli.jar"
@@ -67,6 +80,13 @@ go)
6780
# Usage: generate_go_sdk GENERATOR_PATH GIT_HOST GIT_USER_ID [GIT_REPO_ID] [SDK_REPO_URL]
6881
generate_go_sdk ${jar_path} ${GIT_HOST} ${GIT_USER_ID} ${GIT_REPO_ID} ${SDK_REPO_URL}
6982
;;
83+
python)
84+
echo -e "\nGenerating the Python SDK...\n"
85+
86+
source ${LANGUAGE_GENERATORS_FOLDER_PATH}/${LANGUAGE}.sh
87+
# Usage: generate_python_sdk GENERATOR_PATH GIT_HOST GIT_USER_ID [GIT_REPO_ID] [SDK_REPO_URL]
88+
generate_python_sdk ${jar_path} ${GIT_HOST} ${GIT_USER_ID} ${GIT_REPO_ID} ${SDK_REPO_URL}
89+
;;
7090
*)
7191
echo "SDK language not supported."
7292
exit 1
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#!/bin/bash
2+
# This script clones the SDK repo and updates it with the generated API modules
3+
# Pre-requisites: Java, goimports, Go
4+
set -eo pipefail
5+
6+
ROOT_DIR=$(git rev-parse --show-toplevel)
7+
SDK_REPO_LOCAL_PATH="${ROOT_DIR}/sdk-repo-updated"
8+
9+
OAS_REPO=https://github.com/stackitcloud/stackit-api-specifications
10+
11+
SERVICES_FOLDER="${SDK_REPO_LOCAL_PATH}/services"
12+
13+
GENERATOR_LOG_LEVEL="error" # Must be a Java log level (error, warn, info...)
14+
15+
generate_python_sdk() {
16+
# Required parameters
17+
local GENERATOR_JAR_PATH=$1
18+
local GIT_HOST=$2
19+
local GIT_USER_ID=$3
20+
21+
# Optional parameters
22+
local GIT_REPO_ID=$4
23+
local SDK_REPO_URL=$5
24+
25+
# Check required parameters
26+
if [[ -z ${GIT_HOST} ]]; then
27+
echo "GIT_HOST not specified."
28+
exit 1
29+
fi
30+
31+
if [[ -z ${GIT_USER_ID} ]]; then
32+
echo "GIT_USER_ID id not specified."
33+
exit 1
34+
fi
35+
36+
# Check optional parameters and set defaults if not provided
37+
if [[ -z ${GIT_REPO_ID} ]]; then
38+
echo "GIT_REPO_ID not specified, default will be used."
39+
GIT_REPO_ID="stackit-sdk-python"
40+
fi
41+
42+
if [[ -z ${SDK_REPO_URL} ]]; then
43+
echo "SDK_REPO_URL not specified, default will be used."
44+
SDK_REPO_URL="https://github.com/stackitcloud/stackit-sdk-python.git"
45+
fi
46+
47+
# Prepare folders
48+
if [[ ! -d $SERVICES_FOLDER ]]; then
49+
mkdir -p "$SERVICES_FOLDER"
50+
fi
51+
52+
# Clone SDK repo
53+
if [ -d ${SDK_REPO_LOCAL_PATH} ]; then
54+
echo "Old SDK repo clone was found, it will be removed."
55+
rm -rf ${SDK_REPO_LOCAL_PATH}
56+
fi
57+
git clone --quiet ${SDK_REPO_URL} ${SDK_REPO_LOCAL_PATH}
58+
59+
# Install SDK project tools
60+
cd ${ROOT_DIR}
61+
make project-tools
62+
63+
# Backup of the current state of the SDK services dir (services/)
64+
sdk_services_backup_dir=$(mktemp -d)
65+
if [[ ! ${sdk_services_backup_dir} || -d {sdk_services_backup_dir} ]]; then
66+
echo "Unable to create temporary directory"
67+
exit 1
68+
fi
69+
cleanup() {
70+
rm -rf ${sdk_services_backup_dir}
71+
}
72+
cp -a "${SERVICES_FOLDER}/." ${sdk_services_backup_dir}
73+
74+
# Cleanup after we are done
75+
trap cleanup EXIT
76+
77+
# Remove old contents of services dir (services/)
78+
rm -rf ${SERVICES_FOLDER}
79+
80+
# Generate SDK for each service
81+
for service_json in ${ROOT_DIR}/oas/*.json; do
82+
service="${service_json##*/}"
83+
service="${service%.json}"
84+
85+
# Remove invalid characters to ensure a valid Go pkg name
86+
service="${service//-/}" # remove dashes
87+
service="${service// /}" # remove empty spaces
88+
service="${service//_/}" # remove underscores
89+
service=$(echo "${service}" | tr '[:upper:]' '[:lower:]') # convert upper case letters to lower case
90+
service=$(echo "${service}" | tr -d -c '[:alnum:]') # remove non-alphanumeric characters
91+
92+
echo "Generating \"${service}\" service..."
93+
cd ${ROOT_DIR}
94+
95+
mkdir -p "${SERVICES_FOLDER}/${service}/"
96+
cp "${ROOT_DIR}/scripts/generate-sdk/.openapi-generator-ignore" "${SERVICES_FOLDER}/${service}/"
97+
98+
# Run the generator
99+
java -Dlog.level=${GENERATOR_LOG_LEVEL} -jar ${jar_path} generate \
100+
--generator-name python \
101+
--input-spec "${service_json}" \
102+
--output "${SERVICES_FOLDER}/${service}" \
103+
--package-name "stackit.${service}" \
104+
--template-dir "${ROOT_DIR}/templates/python/" \
105+
--git-host ${GIT_HOST} \
106+
--git-user-id ${GIT_USER_ID} \
107+
--git-repo-id ${GIT_REPO_ID} \
108+
--global-property apis,models,modelTests=false,modelDocs=false,apiDocs=false,apiTests=false,supportingFiles \
109+
--additional-properties=pythonPackageName="stackit-${service},removeEnumValuePrefix=false" >/dev/null
110+
111+
# Remove unnecessary files
112+
rm "${SERVICES_FOLDER}/${service}/.openapi-generator-ignore"
113+
rm -r "${SERVICES_FOLDER}/${service}/.openapi-generator/"
114+
rm "${SERVICES_FOLDER}/${service}/stackit/__init__.py"
115+
rm "${SERVICES_FOLDER}/${service}/.github/workflows/python.yml"
116+
117+
118+
# If the service has a wait package files, move them inside the service folder
119+
if [ -d ${sdk_services_backup_dir}/${service}/wait ]; then
120+
echo "Found ${service} \"wait\" package"
121+
cp -r ${sdk_services_backup_dir}/${service}/wait ${SERVICES_FOLDER}/${service}/wait
122+
fi
123+
124+
# If the service has a CHANGELOG file, move it inside the service folder
125+
if [ -f ${sdk_services_backup_dir}/${service}/CHANGELOG.md ]; then
126+
echo "Found ${service} \"CHANGELOG\" file"
127+
cp -r ${sdk_services_backup_dir}/${service}/CHANGELOG.md ${SERVICES_FOLDER}/${service}/CHANGELOG.md
128+
fi
129+
130+
# If the service has a LICENSE file, move it inside the service folder
131+
if [ -f ${sdk_services_backup_dir}/${service}/LICENSE.md ]; then
132+
echo "Found ${service} \"LICENSE\" file"
133+
cp -r ${sdk_services_backup_dir}/${service}/LICENSE.md ${SERVICES_FOLDER}/${service}/LICENSE.md
134+
fi
135+
136+
# If the service has a NOTICE file, move it inside the service folder
137+
if [ -f ${sdk_services_backup_dir}/${service}/NOTICE.txt ]; then
138+
echo "Found ${service} \"NOTICE\" file"
139+
cp -r ${sdk_services_backup_dir}/${service}/NOTICE.txt ${SERVICES_FOLDER}/${service}/NOTICE.txt
140+
fi
141+
142+
cd ${SERVICES_FOLDER}/${service}
143+
# Run formatter
144+
isort .
145+
autoimport --ignore-init-modules .
146+
black .
147+
148+
done
149+
}

scripts/project.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ elif [ "$action" = "tools" ]; then
1717
cd ${ROOT_DIR}
1818

1919
go install golang.org/x/tools/cmd/goimports@latest
20+
pip install black==24.8.0 isort~=5.13.2 autoimport~=1.6.1
2021
else
2122
echo "Invalid action: '$action', please use $0 help for help"
2223
fi

scripts/sdk-create-pr.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ else
3333
REPO_URL_SSH=$3
3434
fi
3535

36+
if [[ -z $4 ]]; then
37+
echo "LANGUAGE not specified, default will be used."
38+
LANGUAGE="go"
39+
else
40+
LANGUAGE=$4
41+
fi
42+
3643
# Create temp directory to work on
3744
work_dir=$(mktemp -d)
3845
if [[ ! ${work_dir} || -d {work_dir} ]]; then
@@ -83,7 +90,7 @@ for service_path in ${work_dir}/sdk_to_push/services/*; do
8390
fi
8491

8592
git add services/${service}/
86-
if [ ! -d "${work_dir}/sdk_backup/services/${service}/" ]; then # Check if it is a newly added SDK module
93+
if [ "${LANGUAGE}" == "go" ] && [ ! -d "${work_dir}/sdk_backup/services/${service}/" ]; then # Check if it is a newly added SDK module
8794
# go work use -r adds a use directive to the go.work file for dir, if it exists, and removes the use directory if the argument directory doesn’t exist
8895
# the -r flag examines subdirectories of dir recursively
8996
# this prevents errors if there is more than one new module in the SDK generation

0 commit comments

Comments
 (0)