diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 041d76c..f347299 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,9 @@ jobs: - name: Install Hatch run: | python -m pip install hatch==1.15.0 + - name: Install specific version of Virtual Env due to bug with hatch + run: | + python -m pip install virtualenv==20.39.0 - uses: webfactory/ssh-agent@v0.9.1 with: ssh-private-key: ${{ secrets.SDK_KEY }} diff --git a/.github/workflows/create-emulator-pr.yml b/.github/workflows/create-emulator-pr.yml deleted file mode 100644 index ff53a88..0000000 --- a/.github/workflows/create-emulator-pr.yml +++ /dev/null @@ -1,189 +0,0 @@ -name: Create Emulator PR - -on: - pull_request: - branches: [ main ] - types: [opened, synchronize, closed] - -permissions: - contents: read - pull-requests: write - issues: write - -jobs: - cleanup-emulator-pr: - if: github.event.action == 'closed' - runs-on: ubuntu-latest - steps: - - uses: webfactory/ssh-agent@v0.9.1 - with: - ssh-private-key: ${{ secrets.EMULATOR_KEY }} - - - name: Delete emulator branch - run: | - PR_NUMBER="${{ github.event.pull_request.number }}" - EMULATOR_BRANCH="testing-sdk-pr-${PR_NUMBER}-sync" - - git clone git@github.com:aws/aws-durable-execution-emulator.git - cd aws-durable-execution-emulator - git push origin --delete "$EMULATOR_BRANCH" || echo "Branch may not exist" - - create-emulator-pr: - if: github.event.action == 'opened' || github.event.action == 'synchronize' - runs-on: ubuntu-latest - steps: - - name: Checkout testing SDK repo - uses: actions/checkout@v5 - with: - path: testing-sdk - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.13" - - - name: Install uv - uses: astral-sh/setup-uv@v4 - - - uses: webfactory/ssh-agent@v0.9.1 - with: - ssh-private-key: | - ${{ secrets.EMULATOR_PRIVATE_KEY }} - ${{ secrets.SDK_KEY }} - - - name: Checkout emulator repo - run: | - git clone git@github.com:aws/aws-durable-execution-emulator.git emulator - - - name: Create branch and update uv.lock - working-directory: emulator - run: | - # Configure git - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Get PR info - BRANCH_NAME="${{ github.event.pull_request.head.ref }}" - PR_NUMBER="${{ github.event.pull_request.number }}" - EMULATOR_BRANCH="testing-sdk-pr-${PR_NUMBER}-sync" - - # Create or update branch - git fetch origin - if git show-ref --verify --quiet refs/remotes/origin/"$EMULATOR_BRANCH"; then - git checkout "$EMULATOR_BRANCH" - git reset --hard origin/main - else - git checkout -b "$EMULATOR_BRANCH" - fi - - # Update pyproject.toml to use local testing SDK (temporary, not committed) - TESTING_SDK_PATH="$(realpath ../testing-sdk)" - sed -i.bak "s|aws-durable-execution-sdk-python-testing @ git+ssh://git@github.com/aws/aws-durable-execution-sdk-python-testing.git|aws-durable-execution-sdk-python-testing @ file://${TESTING_SDK_PATH}|" pyproject.toml - rm pyproject.toml.bak - - # Generate new uv.lock with the specific testing SDK commit - uv lock - - # Show what changed - echo "=== Changes to be committed ===" - git diff --name-status - git diff uv.lock || echo "uv.lock is a new file" - - # Restore original pyproject.toml (don't commit the temporary change) - git checkout pyproject.toml - - # Commit and push only the uv.lock file - git add uv.lock - if git commit -m "Lock testing SDK branch: $BRANCH_NAME (PR #$PR_NUMBER)"; then - echo "Changes committed successfully" - git push --force-with-lease origin "$EMULATOR_BRANCH" - echo "Branch pushed successfully" - else - echo "No changes to commit" - # Still need to push the branch even if no changes - git push --force-with-lease origin "$EMULATOR_BRANCH" || git push origin "$EMULATOR_BRANCH" - fi - - - name: Create or update PR in emulator repo - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.EMULATOR_REPO_TOKEN }} - script: | - const fs = require('fs'); - const pr = context.payload.pull_request; - const branch_name = pr.head.ref; - const emulator_branch = `testing-sdk-pr-${pr.number}-sync`; - - // Wait a moment for branch to be available - await new Promise(resolve => setTimeout(resolve, 2000)); - - // Read and populate PR template - const template = fs.readFileSync('testing-sdk/.github/workflows/emulator-pr-template.md', 'utf8'); - const pr_body = template - .replace(/{{PR_NUMBER}}/g, pr.number) - .replace(/{{BRANCH_NAME}}/g, branch_name); - - try { - // Check if PR already exists - let existingPR = null; - try { - const prs = await github.rest.pulls.list({ - owner: 'aws', - repo: 'aws-durable-execution-emulator', - head: `aws:${emulator_branch}`, - state: 'open' - }); - existingPR = prs.data[0]; - } catch (e) { - console.log('No existing PR found'); - } - - if (existingPR) { - // Update existing PR - await github.rest.pulls.update({ - owner: 'aws', - repo: 'aws-durable-execution-emulator', - pull_number: existingPR.number, - title: `Lock testing SDK branch: ${branch_name} (PR #${pr.number})`, - body: pr_body - }); - - console.log(`Updated emulator PR: ${existingPR.html_url}`); - - // Comment on original PR about update - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: `🔄 **Emulator PR Updated**\n\nThe emulator PR has been updated with locked dependencies:\n\n➡️ ${existingPR.html_url}` - }); - } else { - // Create new PR - console.log("Creating an emulator PR") - const response = await github.rest.pulls.create({ - owner: 'aws', - repo: 'aws-durable-execution-emulator', - title: `Lock testing SDK branch: ${branch_name} (PR #${pr.number})`, - head: emulator_branch, - base: 'main', - body: pr_body, - draft: true - }); - - console.log(`Created emulator PR: ${response.data.html_url}`); - - // Comment on original PR - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: `🤖 **Emulator PR Created**\n\nA draft PR has been created with locked dependencies:\n\n➡️ ${response.data.html_url}\n\nThe emulator will build binaries using the exact testing SDK commit locked in uv.lock.` - }); - } - - } catch (error) { - console.log(`Error managing PR: ${error.message}`); - console.log(`Error status: ${error.status}`); - console.log(`Error response: ${JSON.stringify(error.response?.data)}`); - core.setFailed(`Failed to manage emulator PR: ${error.message}`); - } diff --git a/.github/workflows/deploy-examples.yml b/.github/workflows/deploy-examples.yml index 754fb01..dfbb752 100644 --- a/.github/workflows/deploy-examples.yml +++ b/.github/workflows/deploy-examples.yml @@ -62,7 +62,9 @@ jobs: - name: Install Hatch run: pip install hatch - + - name: Install specific version of Virtual Env due to bug with hatch + run: | + python -m pip install virtualenv==20.39.0 - name: Build examples run: hatch run examples:build diff --git a/.github/workflows/ecr-release.yml b/.github/workflows/ecr-release.yml new file mode 100644 index 0000000..884b25c --- /dev/null +++ b/.github/workflows/ecr-release.yml @@ -0,0 +1,161 @@ +name: ecr-release.yml +on: + release: + types: [published] + +permissions: + contents: read + id-token: write # This is required for requesting the JWT + +env: + path_to_dockerfile: "DockerFile" + docker_build_dir: "." + aws_region: "us-east-1" + ecr_repository_name: "o4w4w0v6/aws-durable-execution-emulator" + +jobs: + build-and-upload-image-to-ecr: + runs-on: ubuntu-latest + outputs: + full_image_arm64: ${{ steps.build-publish.outputs.full_image_arm64 }} + full_image_x86_64: ${{ steps.build-publish.outputs.full_image_x86_64 }} + ecr_registry_repository: ${{ steps.build-publish.outputs.ecr_registry_repository }} + version: ${{ steps.version.outputs.VERSION }} + strategy: + matrix: + include: + - arch: x86_64 + - arch: arm64 + steps: + - uses: actions/checkout@v6 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install hatch + - name: Set up QEMU for multi-platform builds + if: matrix.arch == 'arm64' + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + - name: Install specific version of Virtual Env due to bug with hatch + run: | + python -m pip install virtualenv==20.39.0 + - name: Build distribution + run: hatch build + - name: pip install + run: | + pip install -e . + - name: Get version from __about__.py + id: version + run: | + VERSION=$(python -c "from aws_durable_execution_sdk_python_testing import __version__; print(__version__)") + echo "VERSION=$VERSION" + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }} + aws-region: ${{ env.aws_region }} + - name: Login to Amazon ECR + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@v2 + with: + registry-type: public + - name: Build, tag, and push image to Amazon ECR + id: build-publish + shell: bash + env: + ECR_REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} + ECR_REPOSITORY: ${{ env.ecr_repository_name }} + IMAGE_TAG: "${{ env.image_tag }}v${{ steps.version.outputs.VERSION }}" + PER_ARCH_IMAGE_TAG: "${{ matrix.arch }}v${{ steps.version.outputs.VERSION }}" + run: | + if [ "${{ matrix.arch }}" = "x86_64" ]; then + docker build --platform linux/amd64 --provenance false "${{ env.docker_build_dir }}" -f "${{ env.path_to_dockerfile }}" -t "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" + else + docker build --platform linux/arm64 --provenance false "${{ env.docker_build_dir }}" -f "${{ env.path_to_dockerfile }}" -t "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" + fi + docker push "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" + echo "IMAGE $PER_ARCH_IMAGE_TAG is pushed to $ECR_REGISTRY/$ECR_REPOSITORY" + echo "image_tag=$PER_ARCH_IMAGE_TAG" + echo "full_image=$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" + echo "ecr_registry_repository=$ECR_REGISTRY/$ECR_REPOSITORY" >> $GITHUB_OUTPUT + echo "full_image_${{ matrix.arch }}=$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" >> $GITHUB_OUTPUT + create-ecr-manifest-per-arch: + runs-on: ubuntu-latest + needs: [build-and-upload-image-to-ecr] + steps: + - name: Grab image, registry/repository name, version from previous steps + id: ecr_names + env: + ECR_REGISTRY_REPOSITORY: ${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }} + FULL_IMAGE_ARM64: ${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }} + FULL_IMAGE_X86_64: ${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }} + VERSION: ${{ needs.build-and-upload-image-to-ecr.outputs.version }} + run: | + echo "full_image_arm64=$FULL_IMAGE_ARM64" + echo "ecr_registry_repository=$ECR_REGISTRY_REPOSITORY" + echo "full_image_x86_64=$FULL_IMAGE_X86_64" + echo "version=$VERSION" + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }} + aws-region: ${{ env.aws_region }} + - name: Login to Amazon ECR + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@v2 + with: + registry-type: public + - name: Create ECR manifest with explicit tag + id: create-ecr-manifest-explicit + run: | + docker manifest create "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:v${{ needs.build-and-upload-image-to-ecr.outputs.version }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" + - name: Annotate ECR manifest with explicit arm64 tag + id: annotate-ecr-manifest-explicit-arm64 + run: | + docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:v${{ needs.build-and-upload-image-to-ecr.outputs.version }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \ + --arch arm64 \ + --os linux + - name: Annotate ECR manifest with explicit amd64 tag + id: annotate-ecr-manifest-explicit-amd64 + run: | + docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:v${{ needs.build-and-upload-image-to-ecr.outputs.version }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \ + --arch amd64 \ + --os linux + - name: Push ECR manifest with explicit version + id: push-ecr-manifest-explicit + run: | + docker manifest push "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:v${{ needs.build-and-upload-image-to-ecr.outputs.version }}" + - name: Create ECR manifest with latest tag + id: create-ecr-manifest-latest + run: | + docker manifest create "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" + - name: Annotate ECR manifest with latest tag arm64 + id: annotate-ecr-manifest-latest-arm64 + run: | + docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \ + --arch arm64 \ + --os linux + - name: Annotate ECR manifest with latest tag amd64 + id: annotate-ecr-manifest-latest-amd64 + run: | + docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \ + "${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \ + --arch amd64 \ + --os linux + - name: Push ECR manifest with latest + id: push-ecr-manifest-latest + run: | + docker manifest push "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \ No newline at end of file diff --git a/.github/workflows/emulator-pr-template.md b/.github/workflows/emulator-pr-template.md deleted file mode 100644 index 96fd09f..0000000 --- a/.github/workflows/emulator-pr-template.md +++ /dev/null @@ -1,11 +0,0 @@ -*Issue #, if available:* Related to aws/aws-durable-execution-sdk-python-testing#{{PR_NUMBER}} - -*Description of changes:* Testing changes from testing SDK branch `{{BRANCH_NAME}}` using locked dependencies in uv.lock - -## Dependencies -This PR locks the testing SDK to a specific commit from branch `{{BRANCH_NAME}}` using uv.lock for reproducible builds. - -PYTHON_LANGUAGE_SDK_BRANCH: main -PYTHON_TESTING_SDK_BRANCH: {{BRANCH_NAME}} - -By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. diff --git a/.gitignore b/.gitignore index ea7c0c4..5fb723c 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ dist/ examples/build/* examples/*.zip + +durable-executions.db* +.coverage diff --git a/DockerFile b/DockerFile new file mode 100644 index 0000000..da35bb2 --- /dev/null +++ b/DockerFile @@ -0,0 +1,18 @@ +FROM python:3.13-slim + +# Copy and install the wheel +COPY dist/*.whl /tmp/ +RUN pip install --no-cache-dir /tmp/*.whl && rm -rf /tmp/*.whl + +# AWS credentials (required for boto3) +ENV AWS_ACCESS_KEY_ID=foo \ + AWS_SECRET_ACCESS_KEY=bar \ + AWS_DEFAULT_REGION=us-east-1 + +CMD ["dex-local-runner", "start-server", \ + "--host", "0.0.0.0", \ + "--port", "9014", \ + "--log-level", "DEBUG", \ + "--lambda-endpoint", "http://host.docker.internal:3001", \ + "--store-type", "sqlite", \ + "--store-path", "/tmp/.durable-executions-local/durable-executions.db"] diff --git a/src/aws_durable_execution_sdk_python_testing/__init__.py b/src/aws_durable_execution_sdk_python_testing/__init__.py index 88b125f..c25db1c 100644 --- a/src/aws_durable_execution_sdk_python_testing/__init__.py +++ b/src/aws_durable_execution_sdk_python_testing/__init__.py @@ -9,6 +9,8 @@ WebRunnerConfig, ) +from aws_durable_execution_sdk_python_testing.__about__ import __version__ + __all__ = [ "DurableChildContextTestRunner", @@ -17,4 +19,5 @@ "DurableFunctionTestRunner", "WebRunner", "WebRunnerConfig", + "__version__", ]