Skip to content

Commit a5b9439

Browse files
committed
Merge branch 'main' of https://github.com/TobikoData/sqlmesh into sung/vscode-env-vars
2 parents 094a953 + 2acf1a2 commit a5b9439

File tree

10 files changed

+485
-146
lines changed

10 files changed

+485
-146
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ on_main_or_tag_filter: &on_main_or_tag_filter
77
branches:
88
only: main
99
tags:
10-
only: /^v.+/
10+
only: /^v\d+\.\d+\.\d+/
1111

1212
on_tag_filter: &on_tag_filter
1313
filters:
1414
branches:
1515
ignore: /.*/
1616
tags:
17-
only: /^v.+/
17+
only: /^v\d+\.\d+\.\d+/
1818

1919
orbs:
2020
path-filtering: circleci/[email protected]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Release VSCode Extension
2+
on:
3+
push:
4+
tags:
5+
- 'vscode@v*'
6+
jobs:
7+
release:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v4
12+
- name: Setup Node.js
13+
uses: actions/setup-node@v4
14+
with:
15+
node-version: '20'
16+
- name: Install pnpm
17+
uses: pnpm/action-setup@v2
18+
with:
19+
version: 10
20+
- name: Install dependencies
21+
run: pnpm install --frozen-lockfile
22+
- name: Extract version from tag
23+
id: extract_version
24+
run: |
25+
VERSION=${GITHUB_REF#refs/tags/vscode@v}
26+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
27+
- name: Update package.json version
28+
working-directory: vscode/extension
29+
run: |
30+
npm version ${{ steps.extract_version.outputs.VERSION }} --no-git-tag-version
31+
- name: Install dependencies
32+
working-directory: vscode/extension
33+
run: pnpm install
34+
- name: Run CI
35+
run: pnpm run ci
36+
- name: Build extension
37+
working-directory: vscode/extension
38+
run: pnpm run vscode:package
39+
- name: Upload extension to Marketplace
40+
working-directory: vscode/extension
41+
run: |
42+
pnpx vsce publish --packagePath sqlmesh-${{ steps.extract_version.outputs.VERSION }}.vsix
43+
env:
44+
VSCE_PAT: ${{ secrets.VSCE_PAT }}

sqlmesh/core/linter/definition.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from collections.abc import Iterator, Iterable, Set, Mapping, Callable
99
from functools import reduce
1010
from sqlmesh.core.model import Model
11-
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range
11+
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix
1212
from sqlmesh.core.console import LinterConsole, get_console
1313

1414
if t.TYPE_CHECKING:
@@ -75,6 +75,7 @@ def lint_model(
7575
model=model,
7676
violation_type="error",
7777
violation_range=violation.violation_range,
78+
fixes=violation.fixes,
7879
)
7980
for violation in error_violations
8081
] + [
@@ -84,6 +85,7 @@ def lint_model(
8485
model=model,
8586
violation_type="warning",
8687
violation_range=violation.violation_range,
88+
fixes=violation.fixes,
8789
)
8890
for violation in warn_violations
8991
]
@@ -152,7 +154,8 @@ def __init__(
152154
model: Model,
153155
violation_type: t.Literal["error", "warning"],
154156
violation_range: t.Optional[Range] = None,
157+
fixes: t.Optional[t.List[Fix]] = None,
155158
) -> None:
156-
super().__init__(rule, violation_msg, violation_range)
159+
super().__init__(rule, violation_msg, violation_range, fixes)
157160
self.model = model
158161
self.violation_type = violation_type

sqlmesh/core/linter/rule.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ class Range:
3939
end: Position
4040

4141

42+
@dataclass(frozen=True)
43+
class TextEdit:
44+
"""A text edit to apply to a file."""
45+
46+
range: Range
47+
new_text: str
48+
49+
50+
@dataclass(frozen=True)
51+
class Fix:
52+
"""A fix that can be applied to resolve a rule violation."""
53+
54+
title: str
55+
edits: t.List[TextEdit]
56+
57+
4258
class _Rule(abc.ABCMeta):
4359
def __new__(cls: Type[_Rule], clsname: str, bases: t.Tuple, attrs: t.Dict) -> _Rule:
4460
attrs["name"] = clsname.lower()
@@ -66,10 +82,14 @@ def violation(
6682
self,
6783
violation_msg: t.Optional[str] = None,
6884
violation_range: t.Optional[Range] = None,
85+
fixes: t.Optional[t.List[Fix]] = None,
6986
) -> RuleViolation:
7087
"""Create a RuleViolation instance for this rule"""
7188
return RuleViolation(
72-
rule=self, violation_msg=violation_msg or self.summary, violation_range=violation_range
89+
rule=self,
90+
violation_msg=violation_msg or self.summary,
91+
violation_range=violation_range,
92+
fixes=fixes,
7393
)
7494

7595
def get_definition_location(self) -> RuleLocation:
@@ -103,11 +123,16 @@ def __repr__(self) -> str:
103123

104124
class RuleViolation:
105125
def __init__(
106-
self, rule: Rule, violation_msg: str, violation_range: t.Optional[Range] = None
126+
self,
127+
rule: Rule,
128+
violation_msg: str,
129+
violation_range: t.Optional[Range] = None,
130+
fixes: t.Optional[t.List[Fix]] = None,
107131
) -> None:
108132
self.rule = rule
109133
self.violation_msg = violation_msg
110134
self.violation_range = violation_range
135+
self.fixes = fixes or []
111136

112137
def __repr__(self) -> str:
113138
return f"{self.rule.name}: {self.violation_msg}"

sqlmesh/core/linter/rules/builtin.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from sqlglot.helper import subclasses
99

1010
from sqlmesh.core.linter.helpers import TokenPositionDetails
11-
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range
11+
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix, TextEdit
1212
from sqlmesh.core.linter.definition import RuleSet
1313
from sqlmesh.core.model import Model, SqlModel
1414

@@ -22,7 +22,8 @@ def check_model(self, model: Model) -> t.Optional[RuleViolation]:
2222
return None
2323
if model.query.is_star:
2424
violation_range = self._get_range(model)
25-
return self.violation(violation_range=violation_range)
25+
fixes = self._create_fixes(model, violation_range)
26+
return self.violation(violation_range=violation_range, fixes=fixes)
2627
return None
2728

2829
def _get_range(self, model: SqlModel) -> t.Optional[Range]:
@@ -37,6 +38,28 @@ def _get_range(self, model: SqlModel) -> t.Optional[Range]:
3738

3839
return None
3940

41+
def _create_fixes(
42+
self, model: SqlModel, violation_range: t.Optional[Range]
43+
) -> t.Optional[t.List[Fix]]:
44+
"""Create fixes for the SELECT * violation."""
45+
if not violation_range:
46+
return None
47+
columns = model.columns_to_types
48+
if not columns:
49+
return None
50+
new_text = ", ".join(columns.keys())
51+
return [
52+
Fix(
53+
title="Replace SELECT * with explicit column list",
54+
edits=[
55+
TextEdit(
56+
range=violation_range,
57+
new_text=new_text,
58+
)
59+
],
60+
)
61+
]
62+
4063

4164
class InvalidSelectStarExpansion(Rule):
4265
def check_model(self, model: Model) -> t.Optional[RuleViolation]:

sqlmesh/core/state_sync/db/environment.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,9 @@ def get_expired_environments(self, current_ts: int) -> t.List[EnvironmentSummary
172172
Returns:
173173
The list of environment summaries to remove.
174174
"""
175-
176-
environment_summaries = self.get_environments_summary()
177-
return [
178-
env_summary
179-
for env_summary in environment_summaries
180-
if env_summary.expiration_ts is not None and env_summary.expiration_ts <= current_ts
181-
]
175+
return self._fetch_environment_summaries(
176+
where=self._create_expiration_filter_expr(current_ts)
177+
)
182178

183179
def delete_expired_environments(
184180
self, current_ts: t.Optional[int] = None
@@ -225,13 +221,7 @@ def get_environments_summary(self) -> t.List[EnvironmentSummary]:
225221
Returns:
226222
A list of all environment summaries.
227223
"""
228-
return [
229-
self._environment_summmary_from_row(row)
230-
for row in fetchall(
231-
self.engine_adapter,
232-
self._environments_query(required_fields=list(EnvironmentSummary.all_fields())),
233-
)
234-
]
224+
return self._fetch_environment_summaries()
235225

236226
def get_environment(
237227
self, environment: str, lock_for_update: bool = False
@@ -327,6 +317,20 @@ def _create_expiration_filter_expr(self, current_ts: int) -> exp.Expression:
327317
expression=exp.Literal.number(current_ts),
328318
)
329319

320+
def _fetch_environment_summaries(
321+
self, where: t.Optional[str | exp.Expression] = None
322+
) -> t.List[EnvironmentSummary]:
323+
return [
324+
self._environment_summmary_from_row(row)
325+
for row in fetchall(
326+
self.engine_adapter,
327+
self._environments_query(
328+
where=where,
329+
required_fields=list(EnvironmentSummary.all_fields()),
330+
),
331+
)
332+
]
333+
330334

331335
def _environment_to_df(environment: Environment) -> pd.DataFrame:
332336
import pandas as pd

sqlmesh/core/state_sync/db/facade.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@
6969
T = t.TypeVar("T")
7070

7171

72-
if t.TYPE_CHECKING:
73-
pass
74-
75-
7672
class EngineAdapterStateSync(StateSync):
7773
"""Manages state of nodes and snapshot with an existing engine adapter.
7874

0 commit comments

Comments
 (0)