From ec6d0481b0721807009352de79903a17c8c49331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A9nes=20Findrik?= Date: Fri, 3 Apr 2026 14:01:08 -0700 Subject: [PATCH 1/4] fix: add dag-folder input and fix root-folder path matching The deploy action's git diff change detection had two bugs: 1. root-folder values with "./" prefix (e.g., "./astro") never matched git diff paths because git omits the "./" prefix 2. Repos where DAGs live outside root-folder in version control (e.g., at "dags/" in the repo root, copied into root-folder at CI time) had their DAG changes silently ignored This adds a `dag-folder` input that specifies where DAGs live in the git repo for change detection purposes. Also normalizes root-folder by stripping "./" prefix and trailing "/" before matching, and switches from regex prefix matching to directory-exact matching to prevent false positives (e.g., "astro" no longer matches "astro-old/"). Fixes #103 Fixes #123 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yaml | 170 +++++++++++++++++- README.md | 34 ++++ action.yaml | 50 +++++- e2e-setup/mocks/dag-folder-git.sh | 16 ++ .../mocks/dag-folder-prefix-no-deploy-git.sh | 16 ++ 5 files changed, 278 insertions(+), 8 deletions(-) create mode 100755 e2e-setup/mocks/dag-folder-git.sh create mode 100644 e2e-setup/mocks/dag-folder-prefix-no-deploy-git.sh diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d1c19fe..42f0dd4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -264,10 +264,178 @@ jobs: image_version_after: ${{ steps.get-deployment-after.outputs.desired_image_version }} hibernation_spec_after: ${{ steps.get-deployment-after.outputs.hibernation_spec }} + dag-folder-deploy-test: + name: DAG Folder Deploy Test + runs-on: ubuntu-latest + needs: [dag-deploy-test, create-test-deployments] + strategy: + matrix: + deployment_id: + [ + "${{ needs.create-test-deployments.outputs.DEPLOYMENT_ID }}", + ] + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Get Astro Environment Info + id: get-astro-env-info + uses: ./.github/workflows/e2e/get_astro_env_info + with: + input_workspace_id: ${{ github.event.inputs.workspace_id }} + input_organization_id: ${{ github.event.inputs.org_id }} + input_astronomer_host: ${{ github.event.inputs.astronomer_host }} + input_astro_api_token: ${{ github.event.inputs.token }} + secret_workspace_id: ${{ secrets.WORKSPACE_ID }} + secret_organization_id: ${{ secrets.ORGANIZATION_ID }} + secret_astronomer_host: ${{ secrets.ASTRONOMER_HOST }} + secret_astro_api_token: ${{ secrets.ASTRO_API_TOKEN }} + + - name: Mock git commands for dag-folder scenario + run: | + # Use mock that returns dags/ paths (outside root-folder) to simulate + # repos where DAGs live at a different location in version control + mv e2e-setup/mocks/dag-folder-git.sh /usr/local/bin/git + chmod +x /usr/local/bin/git + + - name: Install dependencies + run: | + + sudo apt-get install jq + # we need to pre-install the CLI to set the context + mkdir -p "$HOME/.local/bin" + echo "$HOME/.local/bin" >> $GITHUB_PATH + curl -sSL https://raw.githubusercontent.com/astronomer/astro-cli/main/godownloader.sh | bash -s -- -b "$HOME/.local/bin" + + - name: Set CLI context + run: astro context switch ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Get Deployment Info Before Test + id: get-deployment-before + uses: ./.github/workflows/e2e/get_deployment_info + with: + deployment_id: ${{ matrix.deployment_id }} + organization_id: ${{ steps.get-astro-env-info.outputs.organization_id }} + astro_api_token: ${{ steps.get-astro-env-info.outputs.astro_api_token }} + astronomer_host: ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Deploy to Astro with dag-folder + uses: ./ + with: + deployment-id: ${{ matrix.deployment_id }} + workspace: ${{ steps.get-astro-env-info.outputs.workspace_id }} + root-folder: e2e-setup/astro-project + dag-folder: dags + parse: true + + - name: Get Deployment Info After Test + id: get-deployment-after + uses: ./.github/workflows/e2e/get_deployment_info + with: + deployment_id: ${{ matrix.deployment_id }} + organization_id: ${{ steps.get-astro-env-info.outputs.organization_id }} + astro_api_token: ${{ steps.get-astro-env-info.outputs.astro_api_token }} + astronomer_host: ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Validate Deploy Action + uses: ./.github/workflows/e2e/validate_deployment + with: + is_dag_only_deploy: true + dag_tarball_version_before: ${{ steps.get-deployment-before.outputs.desired_dag_tarball_version }} + image_version_before: ${{ steps.get-deployment-before.outputs.desired_image_version }} + hibernation_spec_before: ${{ steps.get-deployment-before.outputs.hibernation_spec }} + dag_tarball_version_after: ${{ steps.get-deployment-after.outputs.desired_dag_tarball_version }} + image_version_after: ${{ steps.get-deployment-after.outputs.desired_image_version }} + hibernation_spec_after: ${{ steps.get-deployment-after.outputs.hibernation_spec }} + + dag-folder-prefix-no-deploy-test: + name: DAG Folder Prefix No Deploy Test + runs-on: ubuntu-latest + needs: [dag-folder-deploy-test, create-test-deployments] + strategy: + matrix: + deployment_id: + [ + "${{ needs.create-test-deployments.outputs.DEPLOYMENT_ID }}", + ] + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Get Astro Environment Info + id: get-astro-env-info + uses: ./.github/workflows/e2e/get_astro_env_info + with: + input_workspace_id: ${{ github.event.inputs.workspace_id }} + input_organization_id: ${{ github.event.inputs.org_id }} + input_astronomer_host: ${{ github.event.inputs.astronomer_host }} + input_astro_api_token: ${{ github.event.inputs.token }} + secret_workspace_id: ${{ secrets.WORKSPACE_ID }} + secret_organization_id: ${{ secrets.ORGANIZATION_ID }} + secret_astronomer_host: ${{ secrets.ASTRONOMER_HOST }} + secret_astro_api_token: ${{ secrets.ASTRO_API_TOKEN }} + + - name: Mock git commands for dag-folder prefix scenario + run: | + # Use mock that returns dags-old/ paths to ensure we only match the + # configured dags/ directory + mv e2e-setup/mocks/dag-folder-prefix-no-deploy-git.sh /usr/local/bin/git + chmod +x /usr/local/bin/git + + - name: Install dependencies + run: | + + sudo apt-get install jq + # we need to pre-install the CLI to set the context + mkdir -p "$HOME/.local/bin" + echo "$HOME/.local/bin" >> $GITHUB_PATH + curl -sSL https://raw.githubusercontent.com/astronomer/astro-cli/main/godownloader.sh | bash -s -- -b "$HOME/.local/bin" + + - name: Set CLI context + run: astro context switch ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Get Deployment Info Before Test + id: get-deployment-before + uses: ./.github/workflows/e2e/get_deployment_info + with: + deployment_id: ${{ matrix.deployment_id }} + organization_id: ${{ steps.get-astro-env-info.outputs.organization_id }} + astro_api_token: ${{ steps.get-astro-env-info.outputs.astro_api_token }} + astronomer_host: ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Deploy to Astro with dag-folder prefix mismatch + uses: ./ + with: + deployment-id: ${{ matrix.deployment_id }} + workspace: ${{ steps.get-astro-env-info.outputs.workspace_id }} + root-folder: e2e-setup/astro-project + dag-folder: dags + parse: true + + - name: Get Deployment Info After Test + id: get-deployment-after + uses: ./.github/workflows/e2e/get_deployment_info + with: + deployment_id: ${{ matrix.deployment_id }} + organization_id: ${{ steps.get-astro-env-info.outputs.organization_id }} + astro_api_token: ${{ steps.get-astro-env-info.outputs.astro_api_token }} + astronomer_host: ${{ steps.get-astro-env-info.outputs.astronomer_host }} + + - name: Validate no image or dag deploy happened + uses: ./.github/workflows/e2e/validate_deployment + with: + is_no_deploy: true + dag_tarball_version_before: ${{ steps.get-deployment-before.outputs.desired_dag_tarball_version }} + image_version_before: ${{ steps.get-deployment-before.outputs.desired_image_version }} + hibernation_spec_before: ${{ steps.get-deployment-before.outputs.hibernation_spec }} + dag_tarball_version_after: ${{ steps.get-deployment-after.outputs.desired_dag_tarball_version }} + image_version_after: ${{ steps.get-deployment-after.outputs.desired_image_version }} + hibernation_spec_after: ${{ steps.get-deployment-after.outputs.hibernation_spec }} + pytests-test: name: Pytest Test runs-on: ubuntu-latest - needs: [dag-deploy-test, create-test-deployments] + needs: [dag-folder-prefix-no-deploy-test, create-test-deployments] strategy: matrix: deployment_id: diff --git a/README.md b/README.md index c80cf1f..3cc0253 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ The following table lists the configuration options for the Deploy to Astro acti | `deployment-name` | `false` | Specifies The name of the deployment you want to make preview from or are deploying too. Cannot be used with `deployment-id` | | `description` | | Configure a description for a deploy to Astro. Description will be visible in the Deploy History tab. | | `root-folder` | `.` | Path to the Astro project, or dbt project for dbt deploys. | +| `dag-folder` | | Path to the DAG folder in the repository, used for change detection when DAGs live outside `root-folder` in version control. When set, file changes under this path are treated as DAG changes during deploy type inference. See [Non-standard repository structures](#non-standard-repository-structures). | | `parse` | `false` | When set to `true`, DAGs are parsed for errors before deploying to Astro. Note that when an image deploy is performed (i.e. `astro deploy`), parsing is also executed by default. Parsing is _not_ performed automatically for DAG-only deploys (i.e. `astro deploy --dags`). | | `pytest` | `false` | When set to `true`, all pytests in the `tests` directory of your Astro project are run before deploying to Astro. See [Run tests with pytest](https://docs.astronomer.io/astro/cli/test-your-astro-project-locally#run-tests-with-pytest) | | `pytest-file` | (all tests run) | Specifies a custom pytest file to run with the pytest command. For example, you could specify `/tests/test-tags.py`.| @@ -144,6 +145,39 @@ steps: root-folder: /example-dags/ ``` +### Non-standard repository structures + +If your DAGs live outside your Astro project in the repository (for example, at the repo root), the action's git-based change detection won't detect DAG changes by default. Use the `dag-folder` input to tell the action where DAGs live in version control. + +In the following example, DAGs are stored at `dags/` in the repo root and copied into the Astro project at CI time: + +```yaml +steps: +- name: checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.after }} + clean: false + +- name: Copy dags into astro folder + run: cp -r dags astro/dags + +- name: Deploy to Astro + uses: astronomer/deploy-action@v0.12.0 + with: + deployment-id: + root-folder: astro + dag-folder: dags + checkout: false +``` + +With this configuration: +- Changes to files under `dags/` are detected as DAG changes (enabling DAG-only deploys) +- `dag-folder` is matched as a directory path, so `dags` matches `dags/...` but not `dags-old/...` +- Changes to files under `astro/` (e.g., `Dockerfile`, `requirements.txt`) trigger a full image deploy +- The `root-folder` is still used to locate the Astro project for the actual deploy command + ### Run Pytests In the following example, the pytest located at `/tests/test-tags.py` runs before deploying to Astro. diff --git a/action.yaml b/action.yaml index 364146d..9868457 100644 --- a/action.yaml +++ b/action.yaml @@ -94,6 +94,10 @@ inputs: required: false default: false description: "Whether to checkout submodules when cloning the repository: `false` to disable (default), `true` to checkout submodules or `recursive` to recursively checkout submodules. Works only when `checkout` is set to `true`." + dag-folder: + required: false + default: "" + description: "Path to the DAG folder in the repository, used for change detection when DAGs live outside root-folder in version control. When set, file changes under this path are treated as DAG changes during deploy type inference. This is useful for repos that copy DAGs into root-folder at CI time." wake-on-deploy: required: false default: false @@ -363,8 +367,13 @@ runs: echo "files changed: $files" fi + # Normalize root-folder: strip leading "./" and trailing "/" since git diff paths don't include them + DBT_ROOT_FOLDER="${{ inputs.root-folder }}" + DBT_ROOT_FOLDER="${DBT_ROOT_FOLDER#./}" + DBT_ROOT_FOLDER="${DBT_ROOT_FOLDER%/}" + for file in $files; do - if [[ $file =~ ^"${{ inputs.root-folder }}".* ]]; then + if [[ "$file" == "$DBT_ROOT_FOLDER" || "$file" == "$DBT_ROOT_FOLDER"/* ]]; then echo $file is part of configured root folder, so would be triggering a dbt deploy DBT_DEPLOY=true fi @@ -403,6 +412,16 @@ runs: SKIP_IMAGE_OR_DAGS_DEPLOY=false files=() + # Normalize root-folder: strip leading "./" and trailing "/" since git diff paths don't include them + ROOT_FOLDER="${{ inputs.root-folder }}" + ROOT_FOLDER="${ROOT_FOLDER#./}" + ROOT_FOLDER="${ROOT_FOLDER%/}" + + # Normalize dag-folder: strip leading "./" and trailing "/" for the same reason + DAG_FOLDER="${{ inputs.dag-folder }}" + DAG_FOLDER="${DAG_FOLDER#./}" + DAG_FOLDER="${DAG_FOLDER%/}" + GITHUB_EVENT_BEFORE=${{ github.event.before }} GITHUB_EVENT_AFTER=${{ github.event.after }} # case when the triggered event is a manual workflow dispatch or a new branch or tag creation, we would need to deploy the image because we cannot determine that it does not need to be deployed @@ -422,20 +441,37 @@ runs: fi for file in $files; do - if [[ $file =~ ^"${{ inputs.root-folder }}".* ]]; then - echo $file is part of the input root folder + FILE_IN_SCOPE=false + IS_DAG_FILE=false + + # Check if file is under root-folder (empty root-folder means all files are in scope) + if [[ "$ROOT_FOLDER" == "" || "$file" == "$ROOT_FOLDER" || "$file" == "$ROOT_FOLDER"/* ]]; then + FILE_IN_SCOPE=true + if [[ $file == *"dags/"* ]]; then + IS_DAG_FILE=true + fi + fi + + # Check if file is under dag-folder (for repos where DAGs live outside root-folder in git) + if [[ "$DAG_FOLDER" != "" && ( "$file" == "$DAG_FOLDER" || "$file" == "$DAG_FOLDER"/* ) ]]; then + FILE_IN_SCOPE=true + IS_DAG_FILE=true + fi + + if [[ $FILE_IN_SCOPE == true ]]; then SKIP_IMAGE_OR_DAGS_DEPLOY=false if [[ ${{ inputs.deploy-type }} == 'infer' ]]; then - if [[ $file == *"dags/"* ]]; then - echo $file is part of dags folder + if [[ $IS_DAG_FILE == true ]]; then + echo "$file is a DAG file" DAGS_ONLY_DEPLOY=true else + echo "$file is a non-DAG file" DAGS_ONLY_DEPLOY=false break fi elif [[ ${{ inputs.deploy-type }} == 'dags-only' ]]; then - if [[ $file == *"dags/"* ]]; then - echo $file is part of dags folder + if [[ $IS_DAG_FILE == true ]]; then + echo "$file is a DAG file" DAGS_ONLY_DEPLOY=true fi elif [[ ${{ inputs.deploy-type }} == 'image-and-dags' ]]; then diff --git a/e2e-setup/mocks/dag-folder-git.sh b/e2e-setup/mocks/dag-folder-git.sh new file mode 100755 index 0000000..9b16857 --- /dev/null +++ b/e2e-setup/mocks/dag-folder-git.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# hack to mock git commands as part of action.yaml so that we could simulate the dag-folder scenario +# where DAGs live outside root-folder in version control (e.g., at dags/ instead of e2e-setup/astro-project/dags/) + +# Check if the script was invoked with "git diff" +if [[ "$1" == "diff" ]]; then + echo "dags/exampledag.py" +elif [[ "$1" == "fetch" ]]; then + echo "Handling git fetch, doing nothing" +elif [[ "$1" == "cat-file" ]]; then + echo "Handling git cat-file, doing nothing" +else + echo "Error: git mock script isn't configured to handle $1" >&2 + exit 1 +fi diff --git a/e2e-setup/mocks/dag-folder-prefix-no-deploy-git.sh b/e2e-setup/mocks/dag-folder-prefix-no-deploy-git.sh new file mode 100644 index 0000000..7d92983 --- /dev/null +++ b/e2e-setup/mocks/dag-folder-prefix-no-deploy-git.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# hack to mock git commands as part of action.yaml so that we could simulate a +# path that shares the dag-folder prefix without actually being inside it + +# Check if the script was invoked with "git diff" +if [[ "$1" == "diff" ]]; then + echo "dags-old/exampledag.py" +elif [[ "$1" == "fetch" ]]; then + echo "Handling git fetch, doing nothing" +elif [[ "$1" == "cat-file" ]]; then + echo "Handling git cat-file, doing nothing" +else + echo "Error: git mock script isn't configured to handle $1" >&2 + exit 1 +fi From 3b113940acd607a9c9d0a2d0f3ce5c0ae94f7740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A9nes=20Findrik?= Date: Mon, 6 Apr 2026 09:23:34 -0700 Subject: [PATCH 2/4] fix: restore dbt root matching and scope e2e secrets --- .../e2e/get_astro_env_info/action.yaml | 33 +++++++++++-------- .github/workflows/tests.yaml | 17 ++++++++-- action.yaml | 3 +- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/.github/workflows/e2e/get_astro_env_info/action.yaml b/.github/workflows/e2e/get_astro_env_info/action.yaml index ef0b734..4cb40da 100644 --- a/.github/workflows/e2e/get_astro_env_info/action.yaml +++ b/.github/workflows/e2e/get_astro_env_info/action.yaml @@ -43,32 +43,37 @@ runs: shell: bash id: get-info run: | + WORKSPACE_ID="${{ inputs.secret_workspace_id }}" if [ "${{ inputs.input_workspace_id }}" != "" ]; then echo "Using provided workspace_id" - echo "WORKSPACE_ID=${{ inputs.input_workspace_id }}" >> $GITHUB_OUTPUT - else - echo "WORKSPACE_ID=${{ inputs.secret_workspace_id }}" >> $GITHUB_OUTPUT + WORKSPACE_ID="${{ inputs.input_workspace_id }}" fi + ORGANIZATION_ID="${{ inputs.secret_organization_id }}" if [ "${{ inputs.input_organization_id }}" != "" ]; then echo "Using provided org_id" - echo "ORGANIZATION_ID=${{ inputs.input_organization_id }}" >> $GITHUB_OUTPUT - else - echo "ORGANIZATION_ID=${{ inputs.secret_organization_id }}" >> $GITHUB_OUTPUT + ORGANIZATION_ID="${{ inputs.input_organization_id }}" fi + ASTRONOMER_HOST="${{ inputs.secret_astronomer_host }}" if [ "${{ inputs.input_astronomer_host }}" != "" ]; then echo "Using provided astronomer_host" - echo "ASTRONOMER_HOST=${{ inputs.input_astronomer_host }}" >> $GITHUB_OUTPUT - else - echo "ASTRONOMER_HOST=${{ inputs.secret_astronomer_host }}" >> $GITHUB_OUTPUT + ASTRONOMER_HOST="${{ inputs.input_astronomer_host }}" fi + ASTRO_API_TOKEN="${{ inputs.secret_astro_api_token }}" if [ "${{ inputs.input_astro_api_token }}" != "" ]; then echo "Using provided token" - echo "ASTRO_API_TOKEN=${{ inputs.input_astro_api_token }}" >> $GITHUB_OUTPUT - echo "ASTRO_API_TOKEN=${{ inputs.input_astro_api_token }}" >> $GITHUB_ENV - else - echo "ASTRO_API_TOKEN=${{ inputs.secret_astro_api_token }}" >> $GITHUB_OUTPUT - echo "ASTRO_API_TOKEN=${{ inputs.secret_astro_api_token }}" >> $GITHUB_ENV + ASTRO_API_TOKEN="${{ inputs.input_astro_api_token }}" fi + + if [ "$WORKSPACE_ID" = "" ] || [ "$ORGANIZATION_ID" = "" ] || [ "$ASTRONOMER_HOST" = "" ] || [ "$ASTRO_API_TOKEN" = "" ]; then + echo "Missing Astro test configuration. Provide workflow inputs or make WORKSPACE_ID, ORGANIZATION_ID, ASTRONOMER_HOST, and ASTRO_API_TOKEN available to this job." >&2 + exit 1 + fi + + echo "WORKSPACE_ID=$WORKSPACE_ID" >> $GITHUB_OUTPUT + echo "ORGANIZATION_ID=$ORGANIZATION_ID" >> $GITHUB_OUTPUT + echo "ASTRONOMER_HOST=$ASTRONOMER_HOST" >> $GITHUB_OUTPUT + echo "ASTRO_API_TOKEN=$ASTRO_API_TOKEN" >> $GITHUB_OUTPUT + echo "ASTRO_API_TOKEN=$ASTRO_API_TOKEN" >> $GITHUB_ENV diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 42f0dd4..a366d6e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -34,6 +34,7 @@ jobs: name: Create Deployment needs: redact-inputs runs-on: ubuntu-latest + environment: e2e-test strategy: matrix: deployment: [deployment-hibernate.yaml, deployment.yaml] @@ -59,11 +60,10 @@ jobs: - name: Install dependencies run: | - - wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && chmod +x /usr/bin/yq - mkdir -p "$HOME/.local/bin" echo "$HOME/.local/bin" >> $GITHUB_PATH + curl -fsSL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o "$HOME/.local/bin/yq" + chmod +x "$HOME/.local/bin/yq" curl -sSL https://raw.githubusercontent.com/astronomer/astro-cli/main/godownloader.sh | bash -s -- -b "$HOME/.local/bin" astro context switch ${{ steps.get-astro-env-info.outputs.astronomer_host }} astro workspace switch ${{ steps.get-astro-env-info.outputs.workspace_id }} @@ -88,6 +88,7 @@ jobs: default-deploy-tests: name: Default Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [create-test-deployments] strategy: max-parallel: 1 @@ -183,6 +184,7 @@ jobs: dag-deploy-test: name: DAG Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [default-deploy-tests, create-test-deployments] strategy: matrix: @@ -267,6 +269,7 @@ jobs: dag-folder-deploy-test: name: DAG Folder Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [dag-deploy-test, create-test-deployments] strategy: matrix: @@ -351,6 +354,7 @@ jobs: dag-folder-prefix-no-deploy-test: name: DAG Folder Prefix No Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [dag-folder-deploy-test, create-test-deployments] strategy: matrix: @@ -435,6 +439,7 @@ jobs: pytests-test: name: Pytest Test runs-on: ubuntu-latest + environment: e2e-test needs: [dag-folder-prefix-no-deploy-test, create-test-deployments] strategy: matrix: @@ -523,6 +528,7 @@ jobs: infer-deploy: name: Infer Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [pytests-test, create-test-deployments] strategy: max-parallel: 1 @@ -617,6 +623,7 @@ jobs: no-deploy-test: name: No Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [infer-deploy, create-test-deployments] strategy: max-parallel: 1 @@ -734,6 +741,7 @@ jobs: custom-docker-image-test: name: Custom Docker Image Test runs-on: ubuntu-latest + environment: e2e-test needs: [no-deploy-test, create-test-deployments] strategy: matrix: @@ -819,6 +827,7 @@ jobs: dbt-deploy-test: name: DBT Deploy Test runs-on: ubuntu-latest + environment: e2e-test needs: [custom-docker-image-test, create-test-deployments] strategy: matrix: @@ -908,6 +917,7 @@ jobs: deployment-preview-test: name: Deployment Preview Test runs-on: ubuntu-latest + environment: e2e-test needs: [create-test-deployments] strategy: matrix: @@ -1158,6 +1168,7 @@ jobs: delete-test-deployments: name: Delete Deployment runs-on: ubuntu-latest + environment: e2e-test needs: [ create-test-deployments, diff --git a/action.yaml b/action.yaml index 9868457..f1b8f13 100644 --- a/action.yaml +++ b/action.yaml @@ -373,7 +373,8 @@ runs: DBT_ROOT_FOLDER="${DBT_ROOT_FOLDER%/}" for file in $files; do - if [[ "$file" == "$DBT_ROOT_FOLDER" || "$file" == "$DBT_ROOT_FOLDER"/* ]]; then + # Empty root-folder means the dbt project lives at the repository root. + if [[ "$DBT_ROOT_FOLDER" == "" || "$file" == "$DBT_ROOT_FOLDER" || "$file" == "$DBT_ROOT_FOLDER"/* ]]; then echo $file is part of configured root folder, so would be triggering a dbt deploy DBT_DEPLOY=true fi From 64d636c82c879cb00007405df92a5c3e6dea9b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A9nes=20Findrik?= Date: Mon, 6 Apr 2026 09:27:47 -0700 Subject: [PATCH 3/4] fix: skip astro e2e jobs when secrets are unavailable --- .github/workflows/tests.yaml | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a366d6e..feab26e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -29,10 +29,44 @@ jobs: TOKEN=$(jq -r '.inputs.token' $GITHUB_EVENT_PATH) echo ::add-mask::$TOKEN + check-astro-test-config: + name: Check Astro Test Config + runs-on: ubuntu-latest + environment: e2e-test + outputs: + has_astro_test_config: ${{ steps.check.outputs.has_astro_test_config }} + steps: + - name: Check Astro test configuration + id: check + env: + SECRET_WORKSPACE_ID: ${{ secrets.WORKSPACE_ID }} + SECRET_ORGANIZATION_ID: ${{ secrets.ORGANIZATION_ID }} + SECRET_ASTRONOMER_HOST: ${{ secrets.ASTRONOMER_HOST }} + SECRET_ASTRO_API_TOKEN: ${{ secrets.ASTRO_API_TOKEN }} + run: | + INPUT_WORKSPACE_ID=$(jq -r '.inputs.workspace_id // empty' "$GITHUB_EVENT_PATH") + INPUT_ORGANIZATION_ID=$(jq -r '.inputs.org_id // empty' "$GITHUB_EVENT_PATH") + INPUT_ASTRONOMER_HOST=$(jq -r '.inputs.astronomer_host // empty' "$GITHUB_EVENT_PATH") + INPUT_ASTRO_API_TOKEN=$(jq -r '.inputs.token // empty' "$GITHUB_EVENT_PATH") + + WORKSPACE_ID="${INPUT_WORKSPACE_ID:-$SECRET_WORKSPACE_ID}" + ORGANIZATION_ID="${INPUT_ORGANIZATION_ID:-$SECRET_ORGANIZATION_ID}" + ASTRONOMER_HOST="${INPUT_ASTRONOMER_HOST:-$SECRET_ASTRONOMER_HOST}" + ASTRO_API_TOKEN="${INPUT_ASTRO_API_TOKEN:-$SECRET_ASTRO_API_TOKEN}" + + if [[ -n "$WORKSPACE_ID" && -n "$ORGANIZATION_ID" && -n "$ASTRONOMER_HOST" && -n "$ASTRO_API_TOKEN" ]]; then + echo "Astro test configuration is available." + echo "has_astro_test_config=true" >> $GITHUB_OUTPUT + else + echo "Astro test configuration is unavailable for this run. Skipping e2e jobs." + echo "has_astro_test_config=false" >> $GITHUB_OUTPUT + fi + # Create test deployments would use the template files and generate deployments with unique names create-test-deployments: name: Create Deployment - needs: redact-inputs + if: ${{ needs.check-astro-test-config.outputs.has_astro_test_config == 'true' }} + needs: [redact-inputs, check-astro-test-config] runs-on: ubuntu-latest environment: e2e-test strategy: @@ -1171,6 +1205,7 @@ jobs: environment: e2e-test needs: [ + check-astro-test-config, create-test-deployments, dag-deploy-test, pytests-test, @@ -1179,7 +1214,7 @@ jobs: deployment-preview-test, ] # ensure that we always try delete the deployment even if any of the tests fail - if: always() + if: ${{ always() && needs.check-astro-test-config.outputs.has_astro_test_config == 'true' }} steps: - name: Checkout code uses: actions/checkout@v6 From 83ad1ab5b227a1b88689328fdffcb2a0e22e7932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A9nes=20Findrik?= Date: Mon, 6 Apr 2026 09:44:54 -0700 Subject: [PATCH 4/4] Handle slash-prefixed dag-folder paths --- .github/workflows/tests.yaml | 4 ++-- README.md | 4 ++-- action.yaml | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index feab26e..a5dba63 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -362,7 +362,7 @@ jobs: deployment-id: ${{ matrix.deployment_id }} workspace: ${{ steps.get-astro-env-info.outputs.workspace_id }} root-folder: e2e-setup/astro-project - dag-folder: dags + dag-folder: /dags/ parse: true - name: Get Deployment Info After Test @@ -447,7 +447,7 @@ jobs: deployment-id: ${{ matrix.deployment_id }} workspace: ${{ steps.get-astro-env-info.outputs.workspace_id }} root-folder: e2e-setup/astro-project - dag-folder: dags + dag-folder: /dags/ parse: true - name: Get Deployment Info After Test diff --git a/README.md b/README.md index 3cc0253..3cb486f 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The following table lists the configuration options for the Deploy to Astro acti | `deployment-name` | `false` | Specifies The name of the deployment you want to make preview from or are deploying too. Cannot be used with `deployment-id` | | `description` | | Configure a description for a deploy to Astro. Description will be visible in the Deploy History tab. | | `root-folder` | `.` | Path to the Astro project, or dbt project for dbt deploys. | -| `dag-folder` | | Path to the DAG folder in the repository, used for change detection when DAGs live outside `root-folder` in version control. When set, file changes under this path are treated as DAG changes during deploy type inference. See [Non-standard repository structures](#non-standard-repository-structures). | +| `dag-folder` | | Path to the DAG folder in the repository, used for change detection when DAGs live outside `root-folder` in version control. Leading `./`, leading `/`, and trailing `/` are ignored for matching. When set, file changes under this path are treated as DAG changes during deploy type inference. See [Non-standard repository structures](#non-standard-repository-structures). | | `parse` | `false` | When set to `true`, DAGs are parsed for errors before deploying to Astro. Note that when an image deploy is performed (i.e. `astro deploy`), parsing is also executed by default. Parsing is _not_ performed automatically for DAG-only deploys (i.e. `astro deploy --dags`). | | `pytest` | `false` | When set to `true`, all pytests in the `tests` directory of your Astro project are run before deploying to Astro. See [Run tests with pytest](https://docs.astronomer.io/astro/cli/test-your-astro-project-locally#run-tests-with-pytest) | | `pytest-file` | (all tests run) | Specifies a custom pytest file to run with the pytest command. For example, you could specify `/tests/test-tags.py`.| @@ -174,7 +174,7 @@ steps: With this configuration: - Changes to files under `dags/` are detected as DAG changes (enabling DAG-only deploys) -- `dag-folder` is matched as a directory path, so `dags` matches `dags/...` but not `dags-old/...` +- `dag-folder` is matched as a directory path, so `dags`, `./dags`, and `/dags/` all match `dags/...` but not `dags-old/...` - Changes to files under `astro/` (e.g., `Dockerfile`, `requirements.txt`) trigger a full image deploy - The `root-folder` is still used to locate the Astro project for the actual deploy command diff --git a/action.yaml b/action.yaml index f1b8f13..bfc18d9 100644 --- a/action.yaml +++ b/action.yaml @@ -418,9 +418,10 @@ runs: ROOT_FOLDER="${ROOT_FOLDER#./}" ROOT_FOLDER="${ROOT_FOLDER%/}" - # Normalize dag-folder: strip leading "./" and trailing "/" for the same reason + # Normalize dag-folder: strip leading "./" or "/" and trailing "/" for the same reason DAG_FOLDER="${{ inputs.dag-folder }}" DAG_FOLDER="${DAG_FOLDER#./}" + DAG_FOLDER="${DAG_FOLDER#/}" DAG_FOLDER="${DAG_FOLDER%/}" GITHUB_EVENT_BEFORE=${{ github.event.before }}