tinybird 0.0.1.dev5__py3-none-any.whl → 0.0.1.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- tinybird/__cli__.py +7 -8
- tinybird/tb/cli.py +28 -0
- tinybird/{tb_cli_modules → tb/modules}/auth.py +5 -5
- tinybird/{tb_cli_modules → tb/modules}/branch.py +5 -25
- tinybird/{tb_cli_modules → tb/modules}/build.py +10 -21
- tinybird/tb/modules/cicd.py +271 -0
- tinybird/{tb_cli_modules → tb/modules}/cli.py +20 -140
- tinybird/tb/modules/common.py +2110 -0
- tinybird/tb/modules/config.py +352 -0
- tinybird/{tb_cli_modules → tb/modules}/connection.py +4 -4
- tinybird/{tb_cli_modules → tb/modules}/create.py +20 -20
- tinybird/tb/modules/datafile/build.py +2103 -0
- tinybird/tb/modules/datafile/build_common.py +118 -0
- tinybird/tb/modules/datafile/build_datasource.py +403 -0
- tinybird/tb/modules/datafile/build_pipe.py +648 -0
- tinybird/tb/modules/datafile/common.py +897 -0
- tinybird/tb/modules/datafile/diff.py +197 -0
- tinybird/tb/modules/datafile/exceptions.py +23 -0
- tinybird/tb/modules/datafile/format_common.py +66 -0
- tinybird/tb/modules/datafile/format_datasource.py +160 -0
- tinybird/tb/modules/datafile/format_pipe.py +195 -0
- tinybird/tb/modules/datafile/parse_datasource.py +41 -0
- tinybird/tb/modules/datafile/parse_pipe.py +69 -0
- tinybird/tb/modules/datafile/pipe_checker.py +560 -0
- tinybird/tb/modules/datafile/pull.py +157 -0
- tinybird/{tb_cli_modules → tb/modules}/datasource.py +7 -6
- tinybird/tb/modules/exceptions.py +91 -0
- tinybird/{tb_cli_modules → tb/modules}/fmt.py +6 -3
- tinybird/{tb_cli_modules → tb/modules}/job.py +3 -3
- tinybird/{tb_cli_modules → tb/modules}/llm.py +1 -1
- tinybird/{tb_cli_modules → tb/modules}/local.py +9 -5
- tinybird/{tb_cli_modules → tb/modules}/mock.py +5 -5
- tinybird/{tb_cli_modules → tb/modules}/pipe.py +11 -5
- tinybird/{tb_cli_modules → tb/modules}/prompts.py +1 -1
- tinybird/tb/modules/regions.py +9 -0
- tinybird/{tb_cli_modules → tb/modules}/tag.py +2 -2
- tinybird/tb/modules/telemetry.py +310 -0
- tinybird/{tb_cli_modules → tb/modules}/test.py +5 -5
- tinybird/{tb_cli_modules → tb/modules}/tinyunit/tinyunit.py +1 -1
- tinybird/{tb_cli_modules → tb/modules}/token.py +3 -3
- tinybird/{tb_cli_modules → tb/modules}/workspace.py +5 -5
- tinybird/{tb_cli_modules → tb/modules}/workspace_members.py +4 -4
- tinybird/tb_cli_modules/common.py +9 -25
- tinybird/tb_cli_modules/config.py +0 -8
- {tinybird-0.0.1.dev5.dist-info → tinybird-0.0.1.dev7.dist-info}/METADATA +1 -1
- tinybird-0.0.1.dev7.dist-info/RECORD +71 -0
- tinybird-0.0.1.dev7.dist-info/entry_points.txt +2 -0
- tinybird/datafile.py +0 -6123
- tinybird/tb_cli.py +0 -28
- tinybird-0.0.1.dev5.dist-info/RECORD +0 -52
- tinybird-0.0.1.dev5.dist-info/entry_points.txt +0 -2
- /tinybird/{tb_cli_modules → tb/modules}/table.py +0 -0
- /tinybird/{tb_cli_modules → tb/modules}/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev5.dist-info → tinybird-0.0.1.dev7.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev5.dist-info → tinybird-0.0.1.dev7.dist-info}/top_level.txt +0 -0
tinybird/__cli__.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
__revision__ = 'b69dd20'
|
|
1
|
+
__name__ = "tinybird-cli"
|
|
2
|
+
__description__ = "Tinybird Command Line Tool"
|
|
3
|
+
__url__ = "https://www.tinybird.co/docs/cli/introduction.html"
|
|
4
|
+
__author__ = "Tinybird"
|
|
5
|
+
__author_email__ = "support@tinybird.co"
|
|
6
|
+
__version__ = "x.y.z"
|
|
7
|
+
__revision__ = "xxxxxxxxx"
|
tinybird/tb/cli.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
if sys.platform == "win32":
|
|
5
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
6
|
+
|
|
7
|
+
import tinybird.tb.modules.auth
|
|
8
|
+
import tinybird.tb.modules.branch
|
|
9
|
+
import tinybird.tb.modules.build
|
|
10
|
+
import tinybird.tb.modules.cli
|
|
11
|
+
import tinybird.tb.modules.common
|
|
12
|
+
import tinybird.tb.modules.connection
|
|
13
|
+
import tinybird.tb.modules.create
|
|
14
|
+
import tinybird.tb.modules.datasource
|
|
15
|
+
import tinybird.tb.modules.fmt
|
|
16
|
+
import tinybird.tb.modules.job
|
|
17
|
+
import tinybird.tb.modules.mock
|
|
18
|
+
import tinybird.tb.modules.pipe
|
|
19
|
+
import tinybird.tb.modules.tag
|
|
20
|
+
import tinybird.tb.modules.test
|
|
21
|
+
import tinybird.tb.modules.token
|
|
22
|
+
import tinybird.tb.modules.workspace
|
|
23
|
+
import tinybird.tb.modules.workspace_members
|
|
24
|
+
|
|
25
|
+
cli = tinybird.tb.modules.cli.cli
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
cli()
|
|
@@ -11,8 +11,8 @@ import humanfriendly.tables
|
|
|
11
11
|
|
|
12
12
|
from tinybird.config import get_display_host
|
|
13
13
|
from tinybird.feedback_manager import FeedbackManager
|
|
14
|
-
from tinybird.
|
|
15
|
-
from tinybird.
|
|
14
|
+
from tinybird.tb.modules.cli import cli
|
|
15
|
+
from tinybird.tb.modules.common import (
|
|
16
16
|
configure_connector,
|
|
17
17
|
coro,
|
|
18
18
|
echo_safe_humanfriendly_tables_format_smart_table,
|
|
@@ -21,9 +21,9 @@ from tinybird.tb_cli_modules.common import (
|
|
|
21
21
|
try_authenticate,
|
|
22
22
|
try_update_config_with_remote,
|
|
23
23
|
)
|
|
24
|
-
from tinybird.
|
|
25
|
-
from tinybird.
|
|
26
|
-
from tinybird.
|
|
24
|
+
from tinybird.tb.modules.config import CLIConfig, ConfigValueOrigin
|
|
25
|
+
from tinybird.tb.modules.exceptions import CLIAuthException
|
|
26
|
+
from tinybird.tb.modules.regions import Region
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@cli.group(invoke_without_command=True)
|
|
@@ -4,17 +4,15 @@
|
|
|
4
4
|
# - But please, **do not** interleave utility functions and command definitions.
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
-
from os import getcwd
|
|
8
7
|
from typing import List, Optional, Tuple
|
|
9
8
|
|
|
10
9
|
import aiofiles
|
|
11
10
|
import click
|
|
12
11
|
import yaml
|
|
13
12
|
|
|
14
|
-
from tinybird.datafile import create_release, wait_job
|
|
15
13
|
from tinybird.feedback_manager import FeedbackManager
|
|
16
|
-
from tinybird.
|
|
17
|
-
from tinybird.
|
|
14
|
+
from tinybird.tb.modules.cli import cli
|
|
15
|
+
from tinybird.tb.modules.common import (
|
|
18
16
|
MAIN_BRANCH,
|
|
19
17
|
OLDEST_ROLLBACK,
|
|
20
18
|
coro,
|
|
@@ -35,9 +33,10 @@ from tinybird.tb_cli_modules.common import (
|
|
|
35
33
|
switch_to_workspace_by_user_workspace_data,
|
|
36
34
|
switch_workspace,
|
|
37
35
|
try_update_config_with_remote,
|
|
36
|
+
wait_job,
|
|
38
37
|
)
|
|
39
|
-
from tinybird.
|
|
40
|
-
from tinybird.
|
|
38
|
+
from tinybird.tb.modules.config import CLIConfig
|
|
39
|
+
from tinybird.tb.modules.exceptions import CLIBranchException, CLIException, CLIReleaseException
|
|
41
40
|
|
|
42
41
|
|
|
43
42
|
@cli.group(hidden=True)
|
|
@@ -129,25 +128,6 @@ set -euxo pipefail
|
|
|
129
128
|
click.echo(FeedbackManager.info_release_generated(semver=semver))
|
|
130
129
|
|
|
131
130
|
|
|
132
|
-
@release.command(name="create", short_help="Create a new Release in deploying status")
|
|
133
|
-
@click.option(
|
|
134
|
-
"--semver",
|
|
135
|
-
is_flag=False,
|
|
136
|
-
required=True,
|
|
137
|
-
type=str,
|
|
138
|
-
help="Semver of the new Release. Example: 1.0.0",
|
|
139
|
-
)
|
|
140
|
-
@coro
|
|
141
|
-
async def release_create(semver: str) -> None:
|
|
142
|
-
click.echo(FeedbackManager.warning_deprecated_releases())
|
|
143
|
-
config = CLIConfig.get_project_config()
|
|
144
|
-
_ = await try_update_config_with_remote(config, only_if_needed=True)
|
|
145
|
-
|
|
146
|
-
client = config.get_client()
|
|
147
|
-
folder = getcwd()
|
|
148
|
-
await create_release(client, config, semver, folder)
|
|
149
|
-
|
|
150
|
-
|
|
151
131
|
@release.command(name="promote", short_help="Promotes to live status a preview Release")
|
|
152
132
|
@click.option(
|
|
153
133
|
"--semver", required=True, type=str, help="Semver of a preview Release to promote to live. Example: 1.0.0"
|
|
@@ -3,7 +3,7 @@ import os
|
|
|
3
3
|
import random
|
|
4
4
|
import time
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any, Awaitable, Callable,
|
|
6
|
+
from typing import Any, Awaitable, Callable, List, Union
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
9
|
import humanfriendly
|
|
@@ -13,23 +13,18 @@ from watchdog.observers import Observer
|
|
|
13
13
|
import tinybird.context as context
|
|
14
14
|
from tinybird.client import TinyB
|
|
15
15
|
from tinybird.config import FeatureFlags
|
|
16
|
-
from tinybird.datafile import (
|
|
17
|
-
ParseException,
|
|
18
|
-
folder_build,
|
|
19
|
-
get_project_filenames,
|
|
20
|
-
has_internal_datafiles,
|
|
21
|
-
parse_datasource,
|
|
22
|
-
parse_pipe,
|
|
23
|
-
)
|
|
24
16
|
from tinybird.feedback_manager import FeedbackManager, bcolors
|
|
25
|
-
from tinybird.
|
|
26
|
-
from tinybird.
|
|
17
|
+
from tinybird.tb.modules.cli import cli
|
|
18
|
+
from tinybird.tb.modules.common import (
|
|
27
19
|
coro,
|
|
28
20
|
)
|
|
29
|
-
from tinybird.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
from tinybird.
|
|
21
|
+
from tinybird.tb.modules.datafile.build import folder_build
|
|
22
|
+
from tinybird.tb.modules.datafile.common import get_project_filenames, has_internal_datafiles
|
|
23
|
+
from tinybird.tb.modules.datafile.exceptions import ParseException
|
|
24
|
+
from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
|
|
25
|
+
from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
26
|
+
from tinybird.tb.modules.local import get_tinybird_local_client
|
|
27
|
+
from tinybird.tb.modules.table import format_table
|
|
33
28
|
|
|
34
29
|
|
|
35
30
|
class FileChangeHandler(FileSystemEventHandler):
|
|
@@ -116,9 +111,6 @@ async def build(
|
|
|
116
111
|
context.disable_template_security_validation.set(True)
|
|
117
112
|
is_internal = has_internal_datafiles(folder)
|
|
118
113
|
tb_client = get_tinybird_local_client()
|
|
119
|
-
workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
|
|
120
|
-
datasources: List[Dict[str, Any]] = await tb_client.datasources()
|
|
121
|
-
pipes: List[Dict[str, Any]] = await tb_client.pipes(dependencies=True)
|
|
122
114
|
|
|
123
115
|
def check_filenames(filenames: List[str]):
|
|
124
116
|
parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
|
|
@@ -142,9 +134,6 @@ async def build(
|
|
|
142
134
|
check_filenames(filenames=filenames)
|
|
143
135
|
await folder_build(
|
|
144
136
|
tb_client,
|
|
145
|
-
workspaces,
|
|
146
|
-
datasources,
|
|
147
|
-
pipes,
|
|
148
137
|
filenames,
|
|
149
138
|
ignore_sql_errors=ignore_sql_errors,
|
|
150
139
|
is_internal=is_internal,
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from os import getcwd
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from tornado.template import Template
|
|
8
|
+
|
|
9
|
+
from tinybird.feedback_manager import FeedbackManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Provider(Enum):
|
|
13
|
+
GitHub = 0
|
|
14
|
+
GitLab = 1
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
WORKFLOW_VERSION = "v3.1.0"
|
|
18
|
+
|
|
19
|
+
DEFAULT_REQUIREMENTS_FILE = "tinybird-cli>=5,<6"
|
|
20
|
+
|
|
21
|
+
GITHUB_CI_YML = """
|
|
22
|
+
name: Tinybird - CI Workflow
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
workflow_dispatch:
|
|
26
|
+
pull_request:
|
|
27
|
+
branches:
|
|
28
|
+
- main
|
|
29
|
+
- master
|
|
30
|
+
types: [opened, reopened, labeled, unlabeled, synchronize, closed]{% if data_project_dir != '.' %}
|
|
31
|
+
paths:
|
|
32
|
+
- '{{ data_project_dir }}/**'{% end %}
|
|
33
|
+
|
|
34
|
+
concurrency: ${{! github.workflow }}-${{! github.event.pull_request.number }}
|
|
35
|
+
|
|
36
|
+
jobs:
|
|
37
|
+
ci:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
defaults:
|
|
40
|
+
run:
|
|
41
|
+
working-directory: '{{ data_project_dir }}'
|
|
42
|
+
services:
|
|
43
|
+
tinybird:
|
|
44
|
+
image: tinybirdco/tinybird-local:latest
|
|
45
|
+
ports:
|
|
46
|
+
- 80:80
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v3
|
|
49
|
+
- name: Install Tinybird CLI
|
|
50
|
+
run: curl -LsSf https://api.tinybird.co/static/install.sh | sh
|
|
51
|
+
- name: Build project
|
|
52
|
+
run: tb build
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
GITLAB_YML = """
|
|
57
|
+
include:
|
|
58
|
+
- local: .gitlab/tinybird/*.yml
|
|
59
|
+
|
|
60
|
+
stages:
|
|
61
|
+
- tests
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
GITLAB_CI_YML = """
|
|
66
|
+
tinybird_ci_workflow:
|
|
67
|
+
stage: tests
|
|
68
|
+
interruptible: true
|
|
69
|
+
needs: []
|
|
70
|
+
rules:
|
|
71
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"{% if data_project_dir != '.' %}
|
|
72
|
+
changes:
|
|
73
|
+
- .gitlab/tinybird/*
|
|
74
|
+
- {{ data_project_dir }}/*
|
|
75
|
+
- {{ data_project_dir }}/**/*{% end %}
|
|
76
|
+
before_script:
|
|
77
|
+
- curl -LsSf https://api.tinybird.co/static/install.sh | sh
|
|
78
|
+
script:
|
|
79
|
+
- cd $CI_PROJECT_DIR/{{ data_project_dir }}
|
|
80
|
+
- tb build
|
|
81
|
+
services:
|
|
82
|
+
- name: tinybirdco/tinybird-local:latest
|
|
83
|
+
alias: tinybird-local
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
EXEC_TEST_SH = """
|
|
88
|
+
#!/usr/bin/env bash
|
|
89
|
+
set -euxo pipefail
|
|
90
|
+
|
|
91
|
+
export TB_VERSION_WARNING=0
|
|
92
|
+
|
|
93
|
+
run_test() {
|
|
94
|
+
t=$1
|
|
95
|
+
echo "** Running $t **"
|
|
96
|
+
echo "** $(cat $t)"
|
|
97
|
+
tmpfile=$(mktemp)
|
|
98
|
+
retries=0
|
|
99
|
+
TOTAL_RETRIES=3
|
|
100
|
+
|
|
101
|
+
# When appending fixtures, we need to retry in case of the data is not replicated in time
|
|
102
|
+
while [ $retries -lt $TOTAL_RETRIES ]; do
|
|
103
|
+
# Run the test and store the output in a temporary file
|
|
104
|
+
bash $t $2 >$tmpfile
|
|
105
|
+
exit_code=$?
|
|
106
|
+
if [ "$exit_code" -eq 0 ]; then
|
|
107
|
+
# If the test passed, break the loop
|
|
108
|
+
if diff -B ${t}.result $tmpfile >/dev/null 2>&1; then
|
|
109
|
+
break
|
|
110
|
+
# If the test failed, increment the retries counter and try again
|
|
111
|
+
else
|
|
112
|
+
retries=$((retries+1))
|
|
113
|
+
fi
|
|
114
|
+
# If the bash command failed, print an error message and break the loop
|
|
115
|
+
else
|
|
116
|
+
break
|
|
117
|
+
fi
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
if diff -B ${t}.result $tmpfile >/dev/null 2>&1; then
|
|
121
|
+
echo "✅ Test $t passed"
|
|
122
|
+
rm $tmpfile
|
|
123
|
+
return 0
|
|
124
|
+
elif [ $retries -eq $TOTAL_RETRIES ]; then
|
|
125
|
+
echo "🚨 ERROR: Test $t failed, diff:";
|
|
126
|
+
diff -B ${t}.result $tmpfile
|
|
127
|
+
rm $tmpfile
|
|
128
|
+
return 1
|
|
129
|
+
else
|
|
130
|
+
echo "🚨 ERROR: Test $t failed with bash command exit code $?"
|
|
131
|
+
cat $tmpfile
|
|
132
|
+
rm $tmpfile
|
|
133
|
+
return 1
|
|
134
|
+
fi
|
|
135
|
+
echo ""
|
|
136
|
+
}
|
|
137
|
+
export -f run_test
|
|
138
|
+
|
|
139
|
+
fail=0
|
|
140
|
+
find ./tests -name "*.test" -print0 | xargs -0 -I {} -P 4 bash -c 'run_test "$@"' _ {} || fail=1
|
|
141
|
+
|
|
142
|
+
if [ $fail == 1 ]; then
|
|
143
|
+
exit -1;
|
|
144
|
+
fi
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
APPEND_FIXTURES_SH = """
|
|
148
|
+
#!/usr/bin/env bash
|
|
149
|
+
set -euxo pipefail
|
|
150
|
+
|
|
151
|
+
directory="datasources/fixtures"
|
|
152
|
+
extensions=("csv" "ndjson")
|
|
153
|
+
|
|
154
|
+
absolute_directory=$(realpath "$directory")
|
|
155
|
+
|
|
156
|
+
for extension in "${extensions[@]}"; do
|
|
157
|
+
file_list=$(find "$absolute_directory" -type f -name "*.$extension")
|
|
158
|
+
|
|
159
|
+
for file_path in $file_list; do
|
|
160
|
+
file_name=$(basename "$file_path")
|
|
161
|
+
file_name_without_extension="${file_name%.*}"
|
|
162
|
+
|
|
163
|
+
command="tb datasource append $file_name_without_extension datasources/fixtures/$file_name"
|
|
164
|
+
echo $command
|
|
165
|
+
$command
|
|
166
|
+
done
|
|
167
|
+
done
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class CICDFile:
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
template: str,
|
|
175
|
+
file_name: str,
|
|
176
|
+
dir_path: Optional[str] = None,
|
|
177
|
+
warning_message: Optional[str] = None,
|
|
178
|
+
):
|
|
179
|
+
self.template = template
|
|
180
|
+
self.file_name = file_name
|
|
181
|
+
self.dir_path = dir_path
|
|
182
|
+
self.warning_message = warning_message
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def full_path(self) -> str:
|
|
186
|
+
return f"{self.dir_path}/{self.file_name}" if self.dir_path else self.file_name
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class CICDGeneratorBase:
|
|
190
|
+
cicd_files: List[CICDFile] = []
|
|
191
|
+
|
|
192
|
+
def __call__(self, path: str, params: Dict[str, Any]):
|
|
193
|
+
for cicd_file in self.cicd_files:
|
|
194
|
+
if cicd_file.dir_path:
|
|
195
|
+
Path(f"{path}/{cicd_file.dir_path}").mkdir(parents=True, exist_ok=True)
|
|
196
|
+
content = Template(cicd_file.template).generate(**params)
|
|
197
|
+
if Path(f"{path}/{cicd_file.full_path}").exists():
|
|
198
|
+
continue
|
|
199
|
+
with open(f"{path}/{cicd_file.full_path}", "wb") as f:
|
|
200
|
+
f.write(content)
|
|
201
|
+
click.echo(FeedbackManager.info_cicd_file_generated(file_path=cicd_file.full_path))
|
|
202
|
+
if cicd_file.warning_message is not None:
|
|
203
|
+
return FeedbackManager.warning_for_cicd_file(
|
|
204
|
+
file_name=cicd_file.file_name, warning_message=cicd_file.warning_message.format(**params)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def is_already_generated(self, path: str) -> bool:
|
|
208
|
+
for cicd_file in self.cicd_files:
|
|
209
|
+
if cicd_file.file_name and Path(f"{path}/{cicd_file.full_path}").exists():
|
|
210
|
+
return True
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def build_generator(cls, provider: str) -> Union["GitHubCICDGenerator", "GitLabCICDGenerator"]:
|
|
215
|
+
builder: Dict[str, Union[Type[GitHubCICDGenerator], Type[GitLabCICDGenerator]]] = {
|
|
216
|
+
Provider.GitHub.name: GitHubCICDGenerator,
|
|
217
|
+
Provider.GitLab.name: GitLabCICDGenerator,
|
|
218
|
+
}
|
|
219
|
+
return builder[provider]()
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class GitHubCICDGenerator(CICDGeneratorBase):
|
|
223
|
+
cicd_files = [
|
|
224
|
+
CICDFile(
|
|
225
|
+
template=GITHUB_CI_YML,
|
|
226
|
+
file_name="tinybird-ci.yml",
|
|
227
|
+
dir_path=".github/workflows",
|
|
228
|
+
),
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class GitLabCICDGenerator(CICDGeneratorBase):
|
|
233
|
+
cicd_files = [
|
|
234
|
+
CICDFile(
|
|
235
|
+
template=GITLAB_YML,
|
|
236
|
+
file_name=".gitlab-ci.yml",
|
|
237
|
+
dir_path=".",
|
|
238
|
+
),
|
|
239
|
+
CICDFile(
|
|
240
|
+
template=GITLAB_CI_YML,
|
|
241
|
+
file_name="tinybird-ci.yml",
|
|
242
|
+
dir_path=".gitlab/tinybird",
|
|
243
|
+
warning_message="Make sure to import the file in your .gitlab-ci.yml file, e.g., `include: '.gitlab/tinybird/*.yml'`.",
|
|
244
|
+
),
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
async def init_cicd(
|
|
249
|
+
path: Optional[str] = None,
|
|
250
|
+
data_project_dir: Optional[str] = None,
|
|
251
|
+
):
|
|
252
|
+
for provider in Provider:
|
|
253
|
+
path = path if path else getcwd()
|
|
254
|
+
data_project_dir = data_project_dir if data_project_dir else "."
|
|
255
|
+
generator = CICDGeneratorBase.build_generator(provider.name)
|
|
256
|
+
params = {
|
|
257
|
+
"data_project_dir": data_project_dir,
|
|
258
|
+
"workflow_version": WORKFLOW_VERSION,
|
|
259
|
+
}
|
|
260
|
+
warning_message = generator(path, params)
|
|
261
|
+
if warning_message:
|
|
262
|
+
click.echo(warning_message)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
async def check_cicd_exists(path: Optional[str] = None) -> Optional[Provider]:
|
|
266
|
+
path = path if path else getcwd()
|
|
267
|
+
for provider in Provider:
|
|
268
|
+
generator = CICDGeneratorBase.build_generator(provider.name)
|
|
269
|
+
if generator.is_already_generated(path):
|
|
270
|
+
return provider
|
|
271
|
+
return None
|
|
@@ -24,32 +24,11 @@ from tinybird.client import (
|
|
|
24
24
|
AuthException,
|
|
25
25
|
AuthNoTokenException,
|
|
26
26
|
DoesNotExistException,
|
|
27
|
-
OperationCanNotBePerformed,
|
|
28
27
|
TinyB,
|
|
29
28
|
)
|
|
30
29
|
from tinybird.config import CURRENT_VERSION, SUPPORTED_CONNECTORS, VERSION, FeatureFlags, get_config
|
|
31
|
-
from tinybird.datafile import (
|
|
32
|
-
AlreadyExistsException,
|
|
33
|
-
CLIGitRelease,
|
|
34
|
-
CLIGitReleaseException,
|
|
35
|
-
Datafile,
|
|
36
|
-
ParseException,
|
|
37
|
-
build_graph,
|
|
38
|
-
create_release,
|
|
39
|
-
diff_command,
|
|
40
|
-
folder_pull,
|
|
41
|
-
folder_push,
|
|
42
|
-
get_project_filenames,
|
|
43
|
-
get_resource_versions,
|
|
44
|
-
has_internal_datafiles,
|
|
45
|
-
parse_datasource,
|
|
46
|
-
parse_pipe,
|
|
47
|
-
parse_token,
|
|
48
|
-
wait_job,
|
|
49
|
-
)
|
|
50
30
|
from tinybird.feedback_manager import FeedbackManager
|
|
51
|
-
from tinybird.
|
|
52
|
-
from tinybird.tb_cli_modules.common import (
|
|
31
|
+
from tinybird.tb.modules.common import (
|
|
53
32
|
OLDEST_ROLLBACK,
|
|
54
33
|
CatchAuthExceptions,
|
|
55
34
|
CLIException,
|
|
@@ -65,9 +44,25 @@ from tinybird.tb_cli_modules.common import (
|
|
|
65
44
|
load_connector_config,
|
|
66
45
|
remove_release,
|
|
67
46
|
try_update_config_with_remote,
|
|
47
|
+
wait_job,
|
|
48
|
+
)
|
|
49
|
+
from tinybird.tb.modules.config import CLIConfig
|
|
50
|
+
from tinybird.tb.modules.datafile.build import build_graph, folder_push
|
|
51
|
+
from tinybird.tb.modules.datafile.common import (
|
|
52
|
+
Datafile,
|
|
53
|
+
get_project_filenames,
|
|
54
|
+
get_resource_versions,
|
|
55
|
+
has_internal_datafiles,
|
|
56
|
+
)
|
|
57
|
+
from tinybird.tb.modules.datafile.diff import diff_command
|
|
58
|
+
from tinybird.tb.modules.datafile.exceptions import (
|
|
59
|
+
AlreadyExistsException,
|
|
60
|
+
ParseException,
|
|
68
61
|
)
|
|
69
|
-
from tinybird.
|
|
70
|
-
from tinybird.
|
|
62
|
+
from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
|
|
63
|
+
from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
64
|
+
from tinybird.tb.modules.datafile.pull import folder_pull
|
|
65
|
+
from tinybird.tb.modules.telemetry import add_telemetry_event
|
|
71
66
|
|
|
72
67
|
__old_click_echo = click.echo
|
|
73
68
|
__old_click_secho = click.secho
|
|
@@ -323,118 +318,8 @@ async def init(
|
|
|
323
318
|
|
|
324
319
|
await folder_init(client, folder, generate_datasources, generate_releases=True, force=force)
|
|
325
320
|
|
|
326
|
-
if not (git or override_commit or cicd):
|
|
327
|
-
return
|
|
328
|
-
|
|
329
|
-
sync_git = git or override_commit
|
|
330
|
-
cli_git_release = None
|
|
331
321
|
error = False
|
|
332
322
|
final_response = None
|
|
333
|
-
try:
|
|
334
|
-
cli_git_release = CLIGitRelease(path=folder)
|
|
335
|
-
except CLIGitReleaseException:
|
|
336
|
-
raise CLIGitReleaseException(FeedbackManager.error_no_git_repo_for_init(repo_path=folder))
|
|
337
|
-
|
|
338
|
-
if sync_git:
|
|
339
|
-
if not cli_git_release.is_main_branch() and not override_commit:
|
|
340
|
-
raise CLIGitReleaseException(FeedbackManager.error_no_git_main_branch())
|
|
341
|
-
|
|
342
|
-
if not cli_git_release.is_dottinyb_ignored():
|
|
343
|
-
raise CLIGitReleaseException(
|
|
344
|
-
FeedbackManager.error_dottinyb_not_ignored(git_working_dir=f"{cli_git_release.working_dir()}/")
|
|
345
|
-
)
|
|
346
|
-
else:
|
|
347
|
-
click.echo(FeedbackManager.info_dottinyb_already_ignored())
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
os.path.exists(f"{cli_git_release.working_dir()}/.diff_tmp")
|
|
351
|
-
and not cli_git_release.is_dotdifftemp_ignored()
|
|
352
|
-
):
|
|
353
|
-
raise CLIGitReleaseException(
|
|
354
|
-
FeedbackManager.error_dotdiff_not_ignored(git_working_dir=f"{cli_git_release.working_dir()}/")
|
|
355
|
-
)
|
|
356
|
-
else:
|
|
357
|
-
click.echo(FeedbackManager.info_dotdifftemp_already_ignored())
|
|
358
|
-
|
|
359
|
-
if "release" not in current_ws:
|
|
360
|
-
raise CLIGitReleaseException(FeedbackManager.error_no_correct_token_for_init())
|
|
361
|
-
|
|
362
|
-
# If we have a release and we are not overriding the commit, we check if we have a release already
|
|
363
|
-
elif current_ws.get("release") and not override_commit:
|
|
364
|
-
final_response = FeedbackManager.error_release_already_set(
|
|
365
|
-
workspace=current_ws["name"], commit=current_ws["release"]["commit"]
|
|
366
|
-
)
|
|
367
|
-
error = True
|
|
368
|
-
|
|
369
|
-
elif override_commit:
|
|
370
|
-
if click.confirm(
|
|
371
|
-
FeedbackManager.prompt_init_git_release_force(
|
|
372
|
-
current_commit=current_ws["release"]["commit"], new_commit=override_commit
|
|
373
|
-
)
|
|
374
|
-
):
|
|
375
|
-
try:
|
|
376
|
-
release = await cli_git_release.update_release(client, current_ws, override_commit)
|
|
377
|
-
except Exception as exc:
|
|
378
|
-
raise CLIGitReleaseException(FeedbackManager.error_exception(error=str(exc)))
|
|
379
|
-
|
|
380
|
-
final_response = FeedbackManager.success_init_git_release(
|
|
381
|
-
workspace_name=current_ws["name"], release_commit=release["commit"]
|
|
382
|
-
)
|
|
383
|
-
else:
|
|
384
|
-
return
|
|
385
|
-
|
|
386
|
-
else:
|
|
387
|
-
click.echo(FeedbackManager.info_no_git_release_yet(workspace=current_ws["name"]))
|
|
388
|
-
click.echo(FeedbackManager.info_diff_resources_for_git_init())
|
|
389
|
-
changed = await diff_command(
|
|
390
|
-
[], True, client, with_print=False, verbose=False, clean_up=True, progress_bar=True
|
|
391
|
-
)
|
|
392
|
-
changed = {
|
|
393
|
-
k: v
|
|
394
|
-
for k, v in changed.items()
|
|
395
|
-
if v is not None and (not ignore_remote or v not in ["remote", "shared"])
|
|
396
|
-
}
|
|
397
|
-
if changed:
|
|
398
|
-
tb_pull_command = "tb pull --force"
|
|
399
|
-
click.echo(FeedbackManager.warning_git_release_init_with_diffs())
|
|
400
|
-
if click.confirm(FeedbackManager.prompt_init_git_release_pull(pull_command=tb_pull_command)):
|
|
401
|
-
await folder_pull(client, folder, auto=True, match=None, force=True)
|
|
402
|
-
|
|
403
|
-
else:
|
|
404
|
-
raise CLIGitReleaseException(
|
|
405
|
-
FeedbackManager.error_diff_resources_for_git_init(
|
|
406
|
-
workspace=current_ws["name"], pull_command=tb_pull_command
|
|
407
|
-
)
|
|
408
|
-
)
|
|
409
|
-
else:
|
|
410
|
-
click.echo(FeedbackManager.info_git_release_init_without_diffs(workspace=current_ws["name"]))
|
|
411
|
-
if cli_git_release.is_dirty_to_init():
|
|
412
|
-
raise CLIGitReleaseException(
|
|
413
|
-
FeedbackManager.error_commit_changes_to_init_release(
|
|
414
|
-
path=cli_git_release.path, git_output=cli_git_release.status()
|
|
415
|
-
)
|
|
416
|
-
)
|
|
417
|
-
try:
|
|
418
|
-
release = await cli_git_release.update_release(client, current_ws)
|
|
419
|
-
except Exception as exc:
|
|
420
|
-
raise CLIGitReleaseException(FeedbackManager.error_exception(error=str(exc)))
|
|
421
|
-
|
|
422
|
-
final_response = FeedbackManager.success_init_git_release(
|
|
423
|
-
workspace_name=current_ws["name"], release_commit=release["commit"]
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
if not override_commit:
|
|
427
|
-
cicd_provider = await check_cicd_exists(cli_git_release.working_dir())
|
|
428
|
-
if not force and cicd_provider:
|
|
429
|
-
if cicd:
|
|
430
|
-
final_response = FeedbackManager.error_cicd_already_exists(provider=cicd_provider.name)
|
|
431
|
-
error = True
|
|
432
|
-
else:
|
|
433
|
-
click.echo(FeedbackManager.info_cicd_already_exists(provider=cicd_provider.name))
|
|
434
|
-
else:
|
|
435
|
-
if cicd:
|
|
436
|
-
data_project_dir = os.path.relpath(folder, cli_git_release.working_dir())
|
|
437
|
-
await init_cicd(client, path=cli_git_release.working_dir(), data_project_dir=data_project_dir)
|
|
438
323
|
|
|
439
324
|
if final_response:
|
|
440
325
|
if error:
|
|
@@ -452,7 +337,7 @@ def check(filenames: List[str], debug: bool) -> None:
|
|
|
452
337
|
filenames = get_project_filenames(".")
|
|
453
338
|
|
|
454
339
|
def process(filenames: Iterable):
|
|
455
|
-
parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource
|
|
340
|
+
parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
|
|
456
341
|
incl_suffix = ".incl"
|
|
457
342
|
try:
|
|
458
343
|
for filename in filenames:
|
|
@@ -1473,11 +1358,6 @@ async def deploy(
|
|
|
1473
1358
|
new_release = True
|
|
1474
1359
|
|
|
1475
1360
|
if new_release:
|
|
1476
|
-
if not dry_run:
|
|
1477
|
-
try:
|
|
1478
|
-
await create_release(client, config, semver)
|
|
1479
|
-
except OperationCanNotBePerformed as e:
|
|
1480
|
-
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1481
1361
|
release_created = True
|
|
1482
1362
|
fork_downstream = True
|
|
1483
1363
|
# allows TB_CHECK_BACKFILL_REQUIRED=0 so it is not checked
|