-
Notifications
You must be signed in to change notification settings - Fork 132
felderize: auto-download the compiler and release #6456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,6 +111,55 @@ jobs: | |
| working-directory: ./python/dbt-feldera | ||
| run: uv cache prune --ci | ||
|
|
||
| # Ideally this would just invoke `publish-python.yml` | ||
| # | ||
| # But not yet supported: | ||
| # https://docs.pypi.org/trusted-publishers/troubleshooting/#reusable-workflows-on-github | ||
| # https://github.com/pypa/gh-action-pypi-publish/issues/166 | ||
| # https://github.com/pypi/warehouse/issues/11096 | ||
| # | ||
| # When this is solved, do this again: | ||
| # - name: "" | ||
| # uses: ./.github/workflows/publish-python.yml | ||
| # secrets: inherit | ||
| publish-felderize: | ||
| runs-on: ubuntu-latest-amd64 | ||
| environment: | ||
| name: release | ||
| url: https://pypi.org/p/felderize | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| defaults: | ||
| run: | ||
| shell: bash | ||
| working-directory: ./python | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@6dfebec6ddbcd197e02256fbdf54deb334fb7f06 # v2 | ||
| with: | ||
| version: "0.11.3" | ||
| enable-cache: true | ||
| - name: "Set up Python" | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | ||
| with: | ||
| python-version: "3.10" | ||
| - name: Install and build felderize | ||
| working-directory: ./python/felderize | ||
| run: | | ||
| uv venv | ||
| uv pip install -e . | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to do pip install -e . explicitly> |
||
| uv build | ||
| - name: Publish felderize | ||
| if: ${{ vars.RELEASE_DRY_RUN == 'false' }} | ||
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e | ||
| with: | ||
| packages-dir: ./python/felderize/dist | ||
| - name: Minimize uv cache | ||
| working-directory: ./python/felderize | ||
| run: uv cache prune --ci | ||
|
|
||
| publish-crates: | ||
| name: "" | ||
| uses: ./.github/workflows/publish-crates.yml | ||
|
|
@@ -162,6 +211,10 @@ jobs: | |
| run: | | ||
| sed -i "s/version = \"${{ env.CURRENT_VERSION }}\"/version = \"${{ env.NEXT_VERSION }}\"/g" pyproject.toml | ||
| sed -i "s/version: '${{ env.CURRENT_VERSION }}'/version: '${{ env.NEXT_VERSION }}'/g" dbt/include/feldera/dbt_project.yml | ||
| - name: Adjust felderize version | ||
| working-directory: ./python/felderize | ||
| run: | | ||
| sed -i "s/version = \"${{ env.CURRENT_VERSION }}\"/version = \"${{ env.NEXT_VERSION }}\"/g" pyproject.toml | ||
| - name: Adjust sql compiler version | ||
| working-directory: ./sql-to-dbsp-compiler/SQL-compiler | ||
| run: | | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,3 +91,38 @@ jobs: | |
| - name: Minimize uv cache | ||
| working-directory: ./python/dbt-feldera | ||
| run: uv cache prune --ci | ||
|
|
||
| deploy-felderize: | ||
| runs-on: ubuntu-latest-amd64 | ||
| environment: | ||
| name: release | ||
| url: https://pypi.org/p/felderize | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| ref: ${{ inputs.tag || github.ref }} | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@6dfebec6ddbcd197e02256fbdf54deb334fb7f06 # v2 | ||
| with: | ||
| version: "0.11.3" | ||
| enable-cache: true | ||
| - name: "Set up Python" | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | ||
| with: | ||
| python-version: "3.10" | ||
| - name: Install and build felderize | ||
| working-directory: ./python/felderize | ||
| run: | | ||
| uv venv | ||
| uv pip install -e . | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need this pip install? build should do it anyways right? |
||
| uv build | ||
| - name: Publish felderize | ||
| if: ${{ vars.RELEASE_DRY_RUN == 'false' }} | ||
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e | ||
| with: | ||
| packages-dir: ./python/felderize/dist | ||
|
|
||
| - name: Minimize uv cache | ||
| working-directory: ./python/felderize | ||
| run: uv cache prune --ci | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ class Config: | |
| feldera_compiler: str = "" | ||
| max_tokens: int = DEFAULT_MAX_TOKENS | ||
| docs_base_url: str = DEFAULT_DOCS_BASE_URL | ||
| auto_download_compiler: bool = True | ||
|
|
||
| @property | ||
| def compiler_path(self) -> str | None: | ||
|
|
@@ -32,6 +33,9 @@ def from_env(cls) -> Config: | |
| load_dotenv(env_path) | ||
|
|
||
| raw_max_tokens = os.environ.get("FELDERIZE_MAX_TOKENS") | ||
| raw_auto_download = ( | ||
| os.environ.get("FELDERIZE_AUTO_DOWNLOAD", "1").strip().lower() | ||
| ) | ||
| return cls( | ||
| model=os.environ.get("FELDERIZE_MODEL", ""), | ||
| api_key=os.environ.get("ANTHROPIC_API_KEY"), | ||
|
|
@@ -41,4 +45,5 @@ def from_env(cls) -> Config: | |
| docs_base_url=os.environ.get( | ||
| "FELDERA_DOCS_BASE_URL", DEFAULT_DOCS_BASE_URL | ||
| ), | ||
| auto_download_compiler=raw_auto_download not in ("0", "false", "no", "off"), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to support all these or should we standardize? |
||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,14 +61,18 @@ def download_compiler( | |
| output_dir: Path | None = None, | ||
| version: str | None = None, | ||
| force: bool = False, | ||
| logs=None, | ||
| ) -> Path: | ||
| """Download sql2dbsp JAR from GitHub releases. Returns the path to the JAR. | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: |
||
| Args: | ||
| output_dir: Directory to save the JAR (default: ~/.felderize/). | ||
| version: Release tag (e.g. "v0.291.0"); defaults to latest. | ||
| force: Overwrite existing file if present. | ||
| logs: Where to write progress messages (default: stdout). Pass | ||
| sys.stderr when stdout must stay machine-clean (e.g. --json-output). | ||
| """ | ||
| out = logs or sys.stdout | ||
| dest_dir = output_dir or FELDERIZE_DIR | ||
| dest_dir.mkdir(parents=True, exist_ok=True) | ||
|
|
||
|
|
@@ -90,7 +94,7 @@ def download_compiler( | |
|
|
||
| if dest.exists() and not force: | ||
| status = "the latest release" if is_latest else "installed" | ||
| print(f"Already on {status}: {name} ({tag})") | ||
| print(f"Already on {status}: {name} ({tag})", file=out) | ||
| return dest | ||
|
|
||
| last_pct = [-1] | ||
|
|
@@ -108,11 +112,70 @@ def _progress(block_num: int, block_size: int, total_size: int) -> None: | |
| f"\r [{bar:<20}] {pct:3d}% {downloaded / 1_048_576:.1f}/{total_size / 1_048_576:.1f} MB", | ||
| end="", | ||
| flush=True, | ||
| file=out, | ||
| ) | ||
|
|
||
| latest_note = " (latest release)" if is_latest else "" | ||
| print(f"Downloading {name} ({tag}){latest_note}...") | ||
| print(f"Downloading {name} ({tag}){latest_note}...", file=out) | ||
| urllib.request.urlretrieve(url, dest, reporthook=_progress) | ||
| print() # newline after progress bar | ||
| print(file=out) # newline after progress bar | ||
|
|
||
| return dest | ||
|
|
||
|
|
||
| def find_local_compiler(search_dir: Path | None = None) -> Path | None: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if there was some network issue or interrupt previously due to which there is truncated / corrupt is this possible? do we prevent corrupt downloads? |
||
| """Return the newest compiler JAR already cached in search_dir. | ||
|
|
||
| Looks for ``sql2dbsp-jar-with-dependencies-*.jar`` files in search_dir | ||
| (default ``~/.felderize/``). Prefers versions felderize supports; among | ||
| those, the highest version. Falls back to the highest unsupported version | ||
| when no supported one is cached (validation then warns). Returns None when | ||
| the directory holds no compiler JAR. | ||
| """ | ||
| directory = search_dir or FELDERIZE_DIR | ||
| if not directory.is_dir(): | ||
| return None | ||
|
|
||
| jars = [p for p in directory.glob(f"{COMPILER_JAR_PREFIX}*.jar") if p.is_file()] | ||
| if not jars: | ||
| return None | ||
|
|
||
| def version_key(path: Path) -> tuple[int, ...]: | ||
| tag = jar_version(path.name) | ||
| return _parse_version(tag) if tag else () | ||
|
|
||
| supported = [ | ||
| p for p in jars if (tag := jar_version(p.name)) and is_supported_version(tag) | ||
| ] | ||
| return max(supported or jars, key=version_key) | ||
|
|
||
|
|
||
| def ensure_compiler( | ||
| search_dir: Path | None = None, | ||
| auto_download: bool = True, | ||
| logs=None, | ||
| ) -> Path | None: | ||
| """Return a usable compiler JAR, downloading the latest one if needed. | ||
|
|
||
| Resolution order: | ||
| 1. The newest compiler JAR already cached in search_dir (~/.felderize/). | ||
| 2. Otherwise, when auto_download is set, download the latest release. | ||
|
|
||
| Returns None when nothing is cached and downloading is disabled or fails; | ||
| callers then fall back to their "compiler not found" handling. | ||
| """ | ||
| local = find_local_compiler(search_dir) | ||
| if local is not None: | ||
| return local | ||
| if not auto_download: | ||
| return None | ||
| try: | ||
| return download_compiler(output_dir=search_dir, logs=logs) | ||
| except Exception as e: # network/API failure — degrade gracefully | ||
| print( | ||
| f"Warning: could not auto-download the Feldera compiler ({e}); " | ||
| "validation will be skipped. Run 'felderize download-compiler' or set " | ||
| "FELDERA_COMPILER to validate.", | ||
| file=sys.stderr, | ||
| ) | ||
| return None | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why pinned hash instead of version?