Skip to content

Generate Libraries #100

Generate Libraries

Generate Libraries #100

name: Generate Libraries
on:
pull_request:
branches:
- '**'
release:
types:
- published
workflow_dispatch:
inputs:
release_name:
description: 'Release name for manual dispatch'
required: true
# Workflow dependencies, also to avoid concurrent commits
# Ref.: https://github.com/orgs/community/discussions/26238
workflow_run:
workflows: ["Generate Model"]
types:
- completed
jobs:
generate-libs:
runs-on: ubuntu-latest
# PyPi trusted publishing | Ref.: https://github.com/pypa/gh-action-pypi-publish?tab=readme-ov-file#trusted-publishing
permissions:
contents: write # For final commit
packages: write # For package upload
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- name: Set RELEASE_VERSION based on the trigger type
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
RELEASE_VERSION="${{ github.ref_name }}"
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
RELEASE_VERSION="${{ github.event.inputs.release_name }}"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Include first chars of commit SHA and run attempt number to avoid collisions
COMMIT_SHA="${{ github.event.pull_request.head.sha }}"
SHORT_COMMIT_SHA=${COMMIT_SHA::7}
RELEASE_VERSION="0.0.0+${{ github.head_ref }}.$SHORT_COMMIT_SHA.${{ github.run_attempt }}"
fi
# Make the RELEASE_VERSION semver compatible (replacing non letter/digit/./+ chars with .)
RELEASE_VERSION=$(echo "$RELEASE_VERSION" | sed 's/[^a-zA-Z0-9\.\+]/./g')
# Display the RELEASE_VERSION for verification
echo "The RELEASE_VERSION is: $RELEASE_VERSION"
# Check if RELEASE_VERSION matches the semver allowed pattern
if [[ ! $RELEASE_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9].* ]]; then
echo "RELEASE_VERSION is NOT semver compatible (1.1.1.xxx)"
exit 1
fi
# Export the RELEASE_VERSION environment variable for future steps (in env.RELEASE_VERSION)
echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Install node env 🏗
uses: actions/setup-node@v4
with:
node-version: 16
- name: Install openapi-generator-cli
run: npm install -g @openapitools/openapi-generator-cli
- name: Cleaning output directories
run: |
rm -r generator_ruby/gem/ generator_python/package/ generator_csharp/package/ || true
- name: Python - Generate classes
working-directory: ./generator_python
run: |
# Iterate over each file in the ./config directory, including the entire subfolder structure
# and then run @openapitools/openapi-generator-cli generate for each file found
# Important notice:
# Results of the find command are sorted in an alphabetic order before being passed to xargs
# This means that since the order of class generation is important, it's necessary to maintain an adequately
# named file structure in the ./config/** directories
# generator-config.json (if exists) -> usecase.generator-config.json -> wrapper.generator-config.json
# Add "| head -n 1" after sort for faster iterations while developing
find ./config/ -type f | sort -n | while read -r file; do npx @openapitools/openapi-generator-cli generate -c "$file" --skip-validate-spec; done
# There seems to be a bug in the handling of datetime & field_validator import in OpenAPI Generator
# ToDo: fix this cleanly with OpenAPI Generator Config
# For now, basic bash script that adds field_validator to all pydantic imports
find ./package/src/hubsante_model -type f -name "*.py" | while read -r file; do
# Check if 'field_validator' is missing in the 'from pydantic import' line
if grep -q 'field_validator' "$file" && ! grep -q '^from pydantic import .*field_validator.*$' "$file"; then
# Add field_validator to the import statement
sed -i '/^from pydantic import /s/$/, field_validator/' "$file"
fi
# Convert datetime to str
sed -i 's/: datetime = Field/: str = Field/g' "$file"
sed -i 's/: Optional\[datetime\] = Field/: Optional[str] = Field/g' "$file"
done
- name: Python - Prepare package files
working-directory: ./generator_python/
run: |
# Add key package files
cp pyproject.toml ./package/
cp README.md ./package/
# Generate __init__.py file to import all the *_wrapper classes
echo "# Auto-generated imports" > ./package/src/hubsante_model/__init__.py
find ./package/src/hubsante_model -type f -name "*_wrapper.py" | while read -r file; do
# Extract the relative path from hubsante_model/
rel_path=${file#*hubsante_model/}
# Convert path to Python import format
import_path=${rel_path%.py}
import_path=${import_path//\//.}
# Add import line
echo "from .$import_path import *" >> ./package/src/hubsante_model/__init__.py
done
- name: Python - Set up
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: Python - Build package
working-directory: ./generator_python/package/
run: |
pip install --upgrade build
# Set correct version
sed -i "s/version = .*/version = \"${{ env.RELEASE_VERSION }}\"/" pyproject.toml
python -m build
- name: Python - Upload package as artifact
uses: actions/upload-artifact@v3
with:
name: python-package-artifact
path: ./generator_python/package/dist/
# Leverages trusted publisher | Ref.: https://docs.pypi.org/trusted-publishers/adding-a-publisher/
- name: Python - Publish package to pypi
uses: pypa/gh-action-pypi-publish@release/v1
if: github.event_name != 'pull_request'
with:
packages-dir: ./generator_python/package/dist/
- name: Ruby - Generate classes
working-directory: ./generator_ruby
run: |
# Iterate over each file in the ./config directory, including the entire subfolder structure
# and then run @openapitools/openapi-generator-cli generate for each file found
# Important notice:
# Results of the find command are sorted in an alphabetic order before being passed to xargs
# This means that since the order of class generation is important, it's necessary to maintain an adequately
# named file structure in the ./config/** directories
# generator-config.json (if exists) -> usecase.generator-config.json -> wrapper.generator-config.json
find ./config/ -type f | sort -n | while read -r file; do npx @openapitools/openapi-generator-cli generate -c "$file" --skip-validate-spec; done
- name: Ruby - Prepare Gem files
working-directory: ./generator_ruby
run: |
# Move generated classes to the correct location
for dir in gem/*/; do
package=$(basename "$dir")
mkdir -p "gem/lib/hubsanteModel/models/$package/"
mv "$dir"/lib/hubsanteModel/models/* "gem/lib/hubsanteModel/models/$package/"
rmdir "$dir/lib/hubsanteModel/models" && rmdir "$dir/lib/hubsanteModel" && rmdir "$dir/lib" && rmdir "$dir"
done;
# Add key gem files
cp hubsante_model.rb gem/lib/hubsanteModel/
cp hubsante_model.gemspec gem/
- name: Ruby - Set up
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
bundler-cache: true
- name: Ruby - Build Gem
working-directory: ./generator_ruby/gem/
run: |
GEM_VERSION=${{ env.RELEASE_VERSION }}
export GEM_VERSION=${GEM_VERSION//+/.}
gem build hubsante_model.gemspec
- name: Ruby - Upload Gem as artifact
uses: actions/upload-artifact@v3
with:
name: ruby-gem-artifact
path: ./generator_ruby/gem/hubsante_model-*.gem
- name: Ruby - Push Gem to GitHub Packages
working-directory: ./generator_ruby/gem/
run: gem push --key github --host https://rubygems.pkg.github.com/ansforge ./hubsante_model-*.gem
env:
GEM_HOST_API_KEY: ${{ secrets.GITHUB_TOKEN }} # GitHub token used to authenticate
- name: C# - Generate classes
working-directory: ./generator_csharp
run: |
# Iterate over each file in the ./config directory, including the entire subfolder structure
# and then run @openapitools/openapi-generator-cli generate for each file found
# Important notice:
# Results of the find command are sorted in an alphabetic order before being passed to xargs
# This means that since the order of class generation is important, it's necessary to maintain an adequately
# named file structure in the ./config/** directories
# generator-config.json (if exists) -> usecase.generator-config.json -> wrapper.generator-config.json
find ./config/ -type f | sort -n | while read -r file; do npx @openapitools/openapi-generator-cli generate -c "$file" --skip-validate-spec; done
# - name: C# - Prepare package files
# working-directory: ./generator_csharp/
# run: |
# # Add key package files
# cp HubsanteModel.csproj ./package/src/
# cp README.md ./package/
# - name: C# - Set up .NET
# uses: actions/setup-dotnet@v3
# with:
# dotnet-version: '6.0.x'
# - name: C# - Build package
# working-directory: ./generator_csharp/package/src/
# run: |
# dotnet restore
# dotnet build --configuration Release
# dotnet pack --configuration Release -p:Version=${{ env.RELEASE_VERSION }}
# - name: C# - Upload package as artifact
# uses: actions/upload-artifact@v3
# with:
# name: csharp-package-artifact
# path: ./generator_csharp/package/src/bin/Release/*.nupkg
# - name: C# - Push package to GitHub Packages
# working-directory: ./generator_csharp/package/src/
# run: |
# dotnet nuget push bin/Release/*.nupkg --source https://nuget.pkg.github.com/ansforge/index.json --api-key ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push changes
if: ${{ !env.ACT }}
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: ⚙️ Auto-génération des librairies