diff --git a/docs/build_recipes/cicd-integration.md b/docs/build_recipes/cicd-integration.md new file mode 100644 index 00000000000..69e6fb261a2 --- /dev/null +++ b/docs/build_recipes/cicd-integration.md @@ -0,0 +1,68 @@ +--- +title: CI/CD Integration +description: Automate Lambda function builds and deployments +--- + + + +Automate your Lambda function builds and deployments using popular CI/CD platforms. These examples show how to build and deploy Lambda functions with Powertools for AWS with proper cross-platform compatibility and deploy them reliably. + +## GitHub Actions + +**GitHub Actions** provides a powerful, integrated CI/CD platform that runs directly in your GitHub repository. It offers excellent integration with AWS services, supports matrix builds for testing multiple configurations, and provides a rich ecosystem of pre-built actions. + +=== "Modern AWS Lambda deploy action" + + ```yaml + --8<-- "examples/build_recipes/cicd/github-actions/deploy-modern.yml" + ``` + +=== "Multi-environment deployment" + + ```yaml + --8<-- "examples/build_recipes/cicd/github-actions/deploy-multi-env.yml" + ``` + +=== "Simple source code deployment" + + ```yaml + --8<-- "examples/build_recipes/cicd/github-actions/deploy-simple.yml" + ``` + +=== "S3 deployment method" + + ```yaml + --8<-- "examples/build_recipes/cicd/github-actions/deploy-s3.yml" + ``` + +=== "Build tool integration" + + ```yaml + --8<-- "examples/build_recipes/cicd/github-actions/deploy-build-tools.yml" + ``` + +## AWS CodeBuild + +**AWS CodeBuild** is a fully managed build service that compiles source code, runs tests, and produces deployment packages. It integrates seamlessly with other AWS services and provides consistent build environments with automatic scaling. + +=== "Basic CodeBuild Configuration" + + ```yaml + --8<-- "examples/build_recipes/cicd/codebuild/buildspec.yml" + ``` + +## Best Practices for CI/CD + +1. **Use Linux runners** (ubuntu-latest) to ensure Lambda compatibility +2. **Cache dependencies** to speed up builds (uv, poetry cache, pip cache) +3. **Run tests first** before building deployment packages +4. **Use matrix builds** to test multiple Python versions or configurations +5. **Implement proper secrets management** with GitHub Secrets or AWS Parameter Store +6. **Add deployment gates** for production environments +7. **Monitor deployment success** with CloudWatch metrics and alarms + +???+ tip "Performance Optimization" + - Use **uv** for fastest dependency installation in CI/CD + - **Cache virtual environments** between builds when possible + - **Parallelize builds** for multiple environments + - **Use container images** for complex dependencies or large packages diff --git a/examples/build_recipes/cicd/codebuild/buildspec-advanced.yml b/examples/build_recipes/cicd/codebuild/buildspec-advanced.yml new file mode 100644 index 00000000000..6441ad958f5 --- /dev/null +++ b/examples/build_recipes/cicd/codebuild/buildspec-advanced.yml @@ -0,0 +1,131 @@ +version: 0.2 + +env: + variables: + PYTHON_VERSION: "3.13" + BUILD_STAGE: "build" + parameter-store: + POWERTOOLS_VERSION: "/build/powertools-version" + +batch: + fast-fail: false + build-list: + - identifier: test + env: + variables: + BUILD_STAGE: "test" + - identifier: build_dev + env: + variables: + BUILD_STAGE: "build" + ENVIRONMENT: "dev" + depend-on: + - test + - identifier: build_prod + env: + variables: + BUILD_STAGE: "build" + ENVIRONMENT: "prod" + depend-on: + - test + +phases: + install: + runtime-versions: + python: $PYTHON_VERSION + commands: + - echo "Build stage: $BUILD_STAGE, Environment: $ENVIRONMENT" + - pip install --upgrade pip uv + + pre_build: + commands: + - | + if [ "$BUILD_STAGE" = "test" ]; then + echo "Installing test dependencies..." + uv venv test-env + source test-env/bin/activate + uv pip install aws-lambda-powertools[all]==$POWERTOOLS_VERSION pytest pytest-cov + cp -r src/ test-src/ + else + echo "Installing build dependencies..." + uv venv build-env + source build-env/bin/activate + uv pip install aws-lambda-powertools[all]==$POWERTOOLS_VERSION + uv pip install pydantic requests + fi + + build: + commands: + - | + if [ "$BUILD_STAGE" = "test" ]; then + echo "Running tests..." + source test-env/bin/activate + cd test-src + pytest tests/ --cov=. --cov-report=xml --cov-report=term + echo "Tests completed successfully" + else + echo "Building deployment package for $ENVIRONMENT..." + source build-env/bin/activate + + # Create environment-specific package + mkdir -p package-$ENVIRONMENT/ + cp -r build-env/lib/python*/site-packages/* package-$ENVIRONMENT/ + cp -r src/* package-$ENVIRONMENT/ + + # Environment-specific optimizations + if [ "$ENVIRONMENT" = "prod" ]; then + echo "Applying production optimizations..." + find package-$ENVIRONMENT/ -name "*.pyc" -delete + find package-$ENVIRONMENT/ -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true + find package-$ENVIRONMENT/ -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true + find package-$ENVIRONMENT/ -name "*.dist-info" -type d -exec rm -rf {} + 2>/dev/null || true + fi + + # Create deployment ZIP + cd package-$ENVIRONMENT && zip -r ../lambda-$ENVIRONMENT.zip . && cd .. + + echo "Package size for $ENVIRONMENT: $(du -sh lambda-$ENVIRONMENT.zip)" + fi + + post_build: + commands: + - | + if [ "$BUILD_STAGE" = "build" ]; then + echo "Deploying to $ENVIRONMENT environment..." + + # Deploy to environment-specific function + aws lambda update-function-code \ + --function-name powertools-app-$ENVIRONMENT \ + --zip-file fileb://lambda-$ENVIRONMENT.zip \ + --region $AWS_DEFAULT_REGION + + # Update environment-specific configuration + LOG_LEVEL="INFO" + if [ "$ENVIRONMENT" = "dev" ]; then + LOG_LEVEL="DEBUG" + fi + + aws lambda update-function-configuration \ + --function-name powertools-app-$ENVIRONMENT \ + --environment Variables="{ + ENVIRONMENT=$ENVIRONMENT, + POWERTOOLS_SERVICE_NAME=powertools-app-$ENVIRONMENT, + POWERTOOLS_METRICS_NAMESPACE=MyApp/$ENVIRONMENT, + POWERTOOLS_LOG_LEVEL=$LOG_LEVEL + }" \ + --region $AWS_DEFAULT_REGION + + echo "Deployment to $ENVIRONMENT completed successfully!" + fi + +artifacts: + files: + - lambda-*.zip + - coverage.xml + name: lambda-artifacts-$(date +%Y-%m-%d-%H-%M-%S) + +cache: + paths: + - 'build-env/**/*' + - 'test-env/**/*' + diff --git a/examples/build_recipes/cicd/codebuild/buildspec.yml b/examples/build_recipes/cicd/codebuild/buildspec.yml new file mode 100644 index 00000000000..3605ba69805 --- /dev/null +++ b/examples/build_recipes/cicd/codebuild/buildspec.yml @@ -0,0 +1,85 @@ +version: 0.2 + +env: + variables: + PYTHON_VERSION: "3.13" + POWERTOOLS_VERSION: "3.18.0" + parameter-store: + FUNCTION_NAME: "/lambda/powertools-app/function-name" + +phases: + install: + runtime-versions: + python: $PYTHON_VERSION + commands: + - echo "Installing build dependencies..." + - pip install --upgrade pip + - pip install uv poetry # Install fast package managers + + pre_build: + commands: + - echo "Pre-build phase started on $(date)" + - echo "Python version: $(python --version)" + - echo "Installing application dependencies..." + + # Use uv for fast dependency installation + - uv venv build-env + - source build-env/bin/activate + - uv pip install aws-lambda-powertools[all]==$POWERTOOLS_VERSION + - uv pip install pydantic requests + + build: + commands: + - echo "Build started on $(date)" + - echo "Creating deployment package..." + + # Create optimized deployment package + - mkdir -p package/ + - cp -r build-env/lib/python*/site-packages/* package/ + - cp -r src/* package/ + + # Remove unnecessary files to reduce package size + - find package/ -name "*.pyc" -delete + - find package/ -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true + - find package/ -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true + - find package/ -name "*.dist-info" -type d -exec rm -rf {} + 2>/dev/null || true + + # Create deployment ZIP + - cd package && zip -r ../lambda-deployment.zip . && cd .. + + # Show package info + - echo "Package size: $(du -sh lambda-deployment.zip)" + - echo "Package contents:" + - unzip -l lambda-deployment.zip | head -20 + + post_build: + commands: + - echo "Build completed on $(date)" + - echo "Deploying Lambda function..." + + # Deploy to Lambda + - aws lambda update-function-code \ + --function-name $FUNCTION_NAME \ + --zip-file fileb://lambda-deployment.zip \ + --region $AWS_DEFAULT_REGION + + # Update environment variables + - aws lambda update-function-configuration \ + --function-name $FUNCTION_NAME \ + --environment Variables="{ + POWERTOOLS_SERVICE_NAME=powertools-codebuild, + POWERTOOLS_METRICS_NAMESPACE=MyApp/CodeBuild, + POWERTOOLS_LOG_LEVEL=INFO + }" \ + --region $AWS_DEFAULT_REGION + + - echo "Deployment completed successfully!" + +artifacts: + files: + - lambda-deployment.zip + name: lambda-deployment-$(date +%Y-%m-%d-%H-%M-%S) + +cache: + paths: + - 'build-env/**/*' # Cache virtual environment for faster builds diff --git a/examples/build_recipes/cicd/github-actions/deploy-build-tools.yml b/examples/build_recipes/cicd/github-actions/deploy-build-tools.yml new file mode 100644 index 00000000000..a9469382955 --- /dev/null +++ b/examples/build_recipes/cicd/github-actions/deploy-build-tools.yml @@ -0,0 +1,92 @@ +name: Deploy with Different Build Tools + +on: + push: + branches: [main] + +jobs: + deploy-poetry: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.13' + + - name: Install Poetry + run: pip install --upgrade pip poetry + + - name: Build with Poetry + run: | + # Create deployment directory + mkdir -p poetry-deploy/ + + # Export and install dependencies + poetry export -f requirements.txt --output requirements.txt --without-hashes + pip install --platform manylinux2014_x86_64 --only-binary=:all: \ + --python-version 3.13 -r requirements.txt -t poetry-deploy/ + + # Copy source code + cp -r src/* poetry-deploy/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: us-east-1 + + - name: Deploy Poetry build + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d + with: + function-name: powertools-poetry-function + code-artifacts-dir: poetry-deploy/ + handler: app.lambda_handler + runtime: python3.13 + environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-poetry","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}' + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} + + deploy-uv: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.13' + + - name: Build with uv (fastest) + run: | + # Install uv + pip install uv + + # Create deployment directory + mkdir -p uv-deploy/ + + # Install dependencies with uv (much faster) + uv pip install \ + --target uv-deploy/ \ + --python-version 3.13 \ + --platform manylinux2014_x86_64 --only-binary=:all: \ + aws-lambda-powertools[all] pydantic requests + + # Copy source code + cp -r src/* uv-deploy/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: us-east-1 + + - name: Deploy uv build + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1 + with: + function-name: powertools-uv-function + code-artifacts-dir: uv-deploy/ + handler: app.lambda_handler + runtime: python3.13 + environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-uv","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}' + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} diff --git a/examples/build_recipes/cicd/github-actions/deploy-modern.yml b/examples/build_recipes/cicd/github-actions/deploy-modern.yml new file mode 100644 index 00000000000..0902f471e16 --- /dev/null +++ b/examples/build_recipes/cicd/github-actions/deploy-modern.yml @@ -0,0 +1,84 @@ +name: Deploy Lambda with AWS Lambda Deploy Action + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + AWS_REGION: us-east-1 + PYTHON_VERSION: '3.13' + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install dependencies + run: | + pip install aws-lambda-powertools[all] pytest pytest-cov + + - name: Run tests + run: | + pytest tests/ --cov=src/ --cov-report=xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./coverage.xml + + deploy: + needs: test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Prepare deployment directory + run: | + # Create deployment directory with dependencies + mkdir -p deploy/ + + # Install dependencies with Linux-compatible wheels + pip install \ + --platform manylinux2014_x86_64 \ + --target deploy/ \ + --implementation cp \ + --python-version ${{ env.PYTHON_VERSION }} \ + --only-binary=:all: \ + --upgrade \ + aws-lambda-powertools[all] pydantic requests + + # Copy application code + cp -r src/* deploy/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ env.AWS_REGION }} + + - name: Deploy to Lambda + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d + with: + function-name: powertools-lambda-function + code-artifacts-dir: deploy/ + handler: app.lambda_handler + runtime: python3.13 + environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-app","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}' + timeout: 30 + memory-size: 512 + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} diff --git a/examples/build_recipes/cicd/github-actions/deploy-multi-env.yml b/examples/build_recipes/cicd/github-actions/deploy-multi-env.yml new file mode 100644 index 00000000000..f1b343bce4a --- /dev/null +++ b/examples/build_recipes/cicd/github-actions/deploy-multi-env.yml @@ -0,0 +1,80 @@ +name: Multi-Environment Lambda Deployment + +on: + push: + branches: [main, develop, staging] + +jobs: + deploy: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - branch: develop + environment: dev + function-suffix: -dev + memory: 256 + timeout: 30 + log-level: DEBUG + - branch: staging + environment: staging + function-suffix: -staging + memory: 512 + timeout: 45 + log-level: INFO + - branch: main + environment: prod + function-suffix: -prod + memory: 1024 + timeout: 60 + log-level: INFO + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + if: github.ref == format('refs/heads/{0}', matrix.branch) + + - name: Set up Python + if: github.ref == format('refs/heads/{0}', matrix.branch) + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.13' + + - name: Prepare deployment with uv (fast) + if: github.ref == format('refs/heads/{0}', matrix.branch) + run: | + # Install uv for fast dependency management + pip install uv + + # Create deployment directory + mkdir -p deploy-${{ matrix.environment }}/ + + # Install dependencies with uv (much faster than pip) + uv pip install \ + --target deploy-${{ matrix.environment }}/ \ + --python-version 3.13 \ + --platform manylinux2014_x86_64 --only-binary=:all: \ + aws-lambda-powertools[all] pydantic requests + + # Copy application code + cp -r src/* deploy-${{ matrix.environment }}/ + + - name: Configure AWS credentials + if: github.ref == format('refs/heads/{0}', matrix.branch) + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: us-east-1 + + - name: Deploy to Lambda + if: github.ref == format('refs/heads/{0}', matrix.branch) + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1 + with: + function-name: powertools-app${{ matrix.function-suffix }} + code-artifacts-dir: deploy-${{ matrix.environment }}/ + handler: app.lambda_handler + runtime: python3.13 + environment: '{"ENVIRONMENT":"${{ matrix.environment }}","POWERTOOLS_SERVICE_NAME":"powertools-app-${{ matrix.environment }}","POWERTOOLS_METRICS_NAMESPACE":"MyApp/${{ matrix.environment }}","POWERTOOLS_LOG_LEVEL":"${{ matrix.log-level }}"}' + timeout: ${{ matrix.timeout }} + memory-size: ${{ matrix.memory }} + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} + tags: '{"Environment":"${{ matrix.environment }}","Project":"powertools-demo","ManagedBy":"github-actions"}' diff --git a/examples/build_recipes/cicd/github-actions/deploy-s3.yml b/examples/build_recipes/cicd/github-actions/deploy-s3.yml new file mode 100644 index 00000000000..72ad1e6c732 --- /dev/null +++ b/examples/build_recipes/cicd/github-actions/deploy-s3.yml @@ -0,0 +1,58 @@ +name: Deploy Lambda via S3 + +on: + push: + branches: [main] + +env: + AWS_REGION: us-east-1 + S3_BUCKET: my-lambda-deployments-bucket + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.13' + + - name: Prepare deployment directory + run: | + mkdir -p lambda-package/ + + # Install Powertools and dependencies + pip install \ + --platform manylinux2014_x86_64 \ + --target lambda-package/ \ + --implementation cp \ + --python-version 3.13 \ + --only-binary=:all: \ + aws-lambda-powertools[all] pydantic requests + + # Copy source code + cp -r src/* lambda-package/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ env.AWS_REGION }} + + - name: Deploy to Lambda via S3 + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1 + with: + function-name: powertools-s3-function + code-artifacts-dir: lambda-package/ + handler: app.lambda_handler + runtime: python3.13 + s3-bucket: ${{ env.S3_BUCKET }} + s3-key: deployments/powertools-function-${{ github.sha }}.zip + environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-s3","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}' + timeout: 30 + memory-size: 512 + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} + publish: true # Publish a new version diff --git a/examples/build_recipes/cicd/github-actions/deploy-simple.yml b/examples/build_recipes/cicd/github-actions/deploy-simple.yml new file mode 100644 index 00000000000..1850bb742d4 --- /dev/null +++ b/examples/build_recipes/cicd/github-actions/deploy-simple.yml @@ -0,0 +1,45 @@ +name: Simple Lambda Deployment from Source + +on: + push: + branches: [main] + +env: + AWS_REGION: us-east-1 + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.13' + + - name: Install dependencies + run: | + # Simple pip install - the action handles the rest + pip install --platform manylinux2014_x86_64 --only-binary=:all: \ + --python-version 3.13 -r requirements.txt -t src-deploy/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ env.AWS_REGION }} + + - name: Deploy to Lambda + uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d + with: + function-name: powertools-simple-function + code-artifacts-dir: src-deploy/ # Deploy from current directory + handler: app.lambda_handler + runtime: python3.13 + environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-simple","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}' + timeout: 30 + memory-size: 512 + role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} + dry-run: false # Set to true for validation without deployment diff --git a/mkdocs.yml b/mkdocs.yml index 2b03168b0e8..bfcee3c8924 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,6 +41,7 @@ nav: - Build recipes: - build_recipes/index.md - Getting started: build_recipes/getting-started.md + - CI/CD integration: build_recipes/cicd-integration.md - Upgrade guide: upgrade.md - We Made This (Community): we_made_this.md - Roadmap: roadmap.md @@ -240,6 +241,7 @@ plugins: Build recipes: - build_recipes/index.md - build_recipes/getting-started.md + - build_recipes/cicd-integration.md - mkdocstrings: default_handler: python
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: