Skip to content
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

Add sql backend + sqlfluff linter #20854

Merged
merged 37 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
80b5fde
Copy as is
grihabor Apr 28, 2024
03c7a2f
Fix imports
grihabor Apr 28, 2024
78d9279
Move register.py
grihabor Apr 28, 2024
ecd06f6
Add tests
grihabor Apr 28, 2024
0760d6e
Fix test_passing and test_failing
grihabor Apr 28, 2024
7b11223
Fix all tests
grihabor Apr 28, 2024
685d11c
Revert changes
grihabor Apr 29, 2024
459506e
Add python tool
grihabor Apr 29, 2024
12ffab5
pants fix src/python/pants/backend/sql::
grihabor Apr 29, 2024
39fd8d1
Move SqlSourceField docstring to help
grihabor Apr 29, 2024
fdd5aee
Remove expected_file_extensions
grihabor Apr 29, 2024
391335a
Remove debug comment
grihabor Apr 29, 2024
57b3b52
pants fix src/python/pants/backend/experimental/sql/::
grihabor Apr 29, 2024
b103645
Add missing __init__.py
grihabor Apr 29, 2024
424f36d
Fix mypy
grihabor Apr 29, 2024
9a95b62
Remove .sql ext
grihabor Apr 29, 2024
2781fff
Make __init__.py empty
grihabor Apr 29, 2024
9e15a43
Skip tests on python 3.7
grihabor Apr 29, 2024
9cb2742
Merge branch 'main' into add-sql-backend
grihabor Apr 30, 2024
5545bc8
Try >=3.9
grihabor Apr 30, 2024
27262f8
Revert "Skip tests on python 3.7"
grihabor Apr 30, 2024
5043c4d
Use dedicated enable_lint_rules flag instead of a hack
grihabor Apr 30, 2024
2c81f09
Revert "Try >=3.9"
grihabor Apr 30, 2024
4c5c961
Try interpreter_constraints on test target
grihabor Apr 30, 2024
73ce94a
CPython==3.9.*
grihabor Apr 30, 2024
19c43fe
Try sqlfluff>=2,<3
grihabor Apr 30, 2024
99b31a6
Fix tests after downgrade
grihabor May 4, 2024
a00fc9e
Merge branch 'main' into add-sql-backend
grihabor May 4, 2024
1b7a732
Add sql docs
grihabor May 6, 2024
d8fa6f6
Update sqlfluff docs
grihabor May 6, 2024
1253956
Better phrasing
grihabor May 6, 2024
8cdd94c
Merge branch 'main' into add-sql-backend
grihabor May 6, 2024
bf4eb4e
Merge branch 'main' into add-sql-backend
grihabor May 8, 2024
bb28732
Add sql backend notes
grihabor May 8, 2024
719bea3
Update section name
grihabor May 8, 2024
fb82f93
Update links
grihabor May 10, 2024
7f4a3bf
Merge branch 'main' into add-sql-backend
grihabor May 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions build-support/bin/generate_builtin_lockfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from pants.backend.python.typecheck.pytype.subsystem import Pytype
from pants.backend.scala.lint.scalafmt.subsystem import ScalafmtSubsystem
from pants.backend.scala.subsystems.scalatest import Scalatest
from pants.backend.sql.lint.sqlfluff.subsystem import Sqlfluff
from pants.backend.terraform.dependency_inference import TerraformHcl2Parser
from pants.backend.tools.semgrep.subsystem import SemgrepSubsystem
from pants.backend.tools.yamllint.subsystem import Yamllint
Expand Down Expand Up @@ -132,6 +133,7 @@ class JvmTool(Tool[JvmToolBase]):
PythonTool(SemgrepSubsystem, "pants.backend.experimental.tools.semgrep"),
PythonTool(Setuptools, "pants.backend.python"),
PythonTool(SetuptoolsSCM, "pants.backend.python"),
PythonTool(Sqlfluff, "pants.backend.experimental.sql.lint.sqlfluff"),
PythonTool(TerraformHcl2Parser, "pants.backend.experimental.terraform"),
PythonTool(TwineSubsystem, "pants.backend.python"),
PythonTool(Yamllint, "pants.backend.experimental.tools.yamllint"),
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/ad-hoc-tools/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Ad-Hoc Tools",
"position": 12
"position": 13
}
2 changes: 1 addition & 1 deletion docs/docs/contributions/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Contributions",
"position": 15
"position": 16
}
2 changes: 1 addition & 1 deletion docs/docs/releases/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Releases",
"position": 14
"position": 15
}
4 changes: 4 additions & 0 deletions docs/docs/sql/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "SQL",
"position": 12
}
54 changes: 54 additions & 0 deletions docs/docs/sql/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: SQL Overview
sidebar_position: 999
---

---

:::caution SQL support is in alpha stage
Pants is currently building support for SQL. Simple use cases might be
supported, but many options are missing.

Please share feedback for what you need to use Pants with your SQL queries by
either [opening a GitHub
issue](https://github.com/pantsbuild/pants/issues/new/choose) or [joining our
Slack](/community/getting-help)!
:::

## Initial setup

First, activate the relevant backend in `pants.toml`:

```toml title="pants.toml"
[GLOBAL]
backend_packages = [
...
"pants.backend.experimental.sql",
...
]
```

The SQL backend adds [`sql_source`](../../reference/targets/sql_source.mdx) and
[`sql_sources`](../../reference/targets/sql_sources.mdx) target types for SQL
files. The [`sql_source`](../../reference/targets/sql_source.mdx) behaves like
[`resource`](../../reference/targets/resource.mdx), so you can use it directly
without wrappers. The `tailor` goal will automatically generate the targets for
your .sql files.

## Enable sqlfluff linter

To enable the linter activate the relevant backend in `pants.toml`:

```toml title="pants.toml"
[GLOBAL]
backend_packages = [
...
"pants.backend.experimental.sql.lint.sqlfluff",
...
]
```

You can run the linter via `lint` goal:
```
pants lint --only=sqlfluff ::
```
2 changes: 1 addition & 1 deletion docs/docs/writing-plugins/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Writing Plugins",
"position": 13
"position": 14
}
6 changes: 6 additions & 0 deletions docs/notes/2.22.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ If you encounter such discrepancies, and you can't resolve them easily, please [

### Backends

#### NEW: SQL

A new experimental `SQL` backend was added along with the [sqlfluff
linter](https://www.pantsbuild.org/2.22/reference/subsystems/sqlfluff). See
docs [here](https://www.pantsbuild.org/2.22/docs/sql).

#### JVM

##### Scala
Expand Down
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from pants.backend.sql.lint.sqlfluff import rules as sqlfluff_rules
from pants.backend.sql.lint.sqlfluff import skip_field, subsystem


def rules():
return [
*subsystem.rules(),
*sqlfluff_rules.rules(),
*skip_field.rules(),
]
15 changes: 15 additions & 0 deletions src/python/pants/backend/experimental/sql/register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from pants.backend.sql import tailor
from pants.backend.sql.target_types import SqlSourcesGeneratorTarget, SqlSourceTarget


def target_types():
return [
SqlSourceTarget,
SqlSourcesGeneratorTarget,
]


def rules():
return [*tailor.rules()]
9 changes: 9 additions & 0 deletions src/python/pants/backend/sql/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

python_sources(
sources=[
"tailor.py",
"target_types.py",
],
)
Empty file.
Empty file.
11 changes: 11 additions & 0 deletions src/python/pants/backend/sql/lint/sqlfluff/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
resource(name="lockfile", source="sqlfluff.lock")

python_sources(
overrides={"subsystem.py": {"dependencies": [":lockfile"]}},
)

python_tests(
name="tests",
)
Empty file.
144 changes: 144 additions & 0 deletions src/python/pants/backend/sql/lint/sqlfluff/rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Tuple

from typing_extensions import assert_never

from pants.backend.python.util_rules import pex
from pants.backend.python.util_rules.pex import PexRequest, VenvPex, VenvPexProcess
from pants.backend.sql.lint.sqlfluff.subsystem import Sqlfluff, SqlfluffFieldSet, SqlfluffMode
from pants.core.goals.fix import FixResult, FixTargetsRequest
from pants.core.goals.fmt import FmtResult, FmtTargetsRequest
from pants.core.goals.lint import LintResult, LintTargetsRequest
from pants.core.util_rules.config_files import ConfigFiles, ConfigFilesRequest
from pants.core.util_rules.partitions import PartitionerType
from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
from pants.engine.fs import Digest, MergeDigests
from pants.engine.internals.native_engine import Snapshot
from pants.engine.process import FallibleProcessResult
from pants.engine.rules import Get, MultiGet, collect_rules, rule
from pants.util.logging import LogLevel
from pants.util.meta import classproperty
from pants.util.strutil import pluralize


class SqlfluffFixRequest(FixTargetsRequest):
field_set_type = SqlfluffFieldSet
tool_subsystem = Sqlfluff
partitioner_type = PartitionerType.DEFAULT_SINGLE_PARTITION

# We don't need to include automatically added lint rules for this SqlfluffFixRequest,
# because these lint rules are already checked by SqlfluffLintRequest.
enable_lint_rules = False


class SqlfluffLintRequest(LintTargetsRequest):
field_set_type = SqlfluffFieldSet
tool_subsystem = Sqlfluff
partitioner_type = PartitionerType.DEFAULT_SINGLE_PARTITION


class SqlfluffFormatRequest(FmtTargetsRequest):
field_set_type = SqlfluffFieldSet
tool_subsystem = Sqlfluff
partitioner_type = PartitionerType.DEFAULT_SINGLE_PARTITION

@classproperty
def tool_name(cls) -> str:
return "sqlfluff format"

@classproperty
def tool_id(cls) -> str:
return "sqlfluff-format"


@dataclass(frozen=True)
class _RunSqlfluffRequest:
snapshot: Snapshot
mode: SqlfluffMode


@rule(level=LogLevel.DEBUG)
async def run_sqlfluff(
request: _RunSqlfluffRequest,
sqlfluff: Sqlfluff,
) -> FallibleProcessResult:
sqlfluff_pex_get = Get(VenvPex, PexRequest, sqlfluff.to_pex_request())

config_files_get = Get(
ConfigFiles, ConfigFilesRequest, sqlfluff.config_request(request.snapshot.dirs)
)

sqlfluff_pex, config_files = await MultiGet(sqlfluff_pex_get, config_files_get)

input_digest = await Get(
Digest,
MergeDigests((request.snapshot.digest, config_files.snapshot.digest)),
)

initial_args: Tuple[str, ...] = ()
if request.mode is SqlfluffMode.FMT:
initial_args = ("format",)
elif request.mode is SqlfluffMode.FIX:
initial_args = ("fix", *sqlfluff.fix_args)
elif request.mode is SqlfluffMode.LINT:
initial_args = ("lint",)
else:
assert_never(request.mode)

conf_args = ["--config", sqlfluff.config] if sqlfluff.config else []

result = await Get(
FallibleProcessResult,
VenvPexProcess(
sqlfluff_pex,
argv=(*initial_args, *conf_args, *sqlfluff.args, *request.snapshot.files),
input_digest=input_digest,
output_files=request.snapshot.files,
description=f"Run sqlfluff {' '.join(initial_args)} on {pluralize(len(request.snapshot.files), 'file')}.",
level=LogLevel.DEBUG,
),
)
return result


@rule(desc="Fix with sqlfluff fix", level=LogLevel.DEBUG)
async def sqlfluff_fix(request: SqlfluffFixRequest.Batch, sqlfluff: Sqlfluff) -> FixResult:
result = await Get(
FallibleProcessResult, _RunSqlfluffRequest(snapshot=request.snapshot, mode=SqlfluffMode.FIX)
)
return await FixResult.create(request, result)


@rule(desc="Lint with sqlfluff lint", level=LogLevel.DEBUG)
async def sqlfluff_lint(request: SqlfluffLintRequest.Batch[SqlfluffFieldSet, Any]) -> LintResult:
source_files = await Get(
SourceFiles, SourceFilesRequest(field_set.source for field_set in request.elements)
)
result = await Get(
FallibleProcessResult,
_RunSqlfluffRequest(snapshot=source_files.snapshot, mode=SqlfluffMode.LINT),
)
return LintResult.create(request, result)


@rule(desc="Format with sqlfluff format", level=LogLevel.DEBUG)
async def sqlfluff_fmt(request: SqlfluffFormatRequest.Batch, sqlfluff: Sqlfluff) -> FmtResult:
result = await Get(
FallibleProcessResult,
_RunSqlfluffRequest(snapshot=request.snapshot, mode=SqlfluffMode.FMT),
)
return await FmtResult.create(request, result)


def rules():
return [
*collect_rules(),
*SqlfluffLintRequest.rules(),
*SqlfluffFixRequest.rules(),
*SqlfluffFormatRequest.rules(),
*pex.rules(),
]