Skip to content

Commit b44b5be

Browse files
committed
Add mechanism to suspend providers
As agreed in https://lists.apache.org/thread/g8b3k028qhzgw6c3yz4jvmlc67kcr9hj we introduce mechanism to suspend providers from our suite of providers when they are holding us back to older version of dependencies. Provider's suspension is controlled from a single `suspend` flag in `provider.yaml` - this flag is used to generate providers_dependencies.json in generated folders (provider is skipped if it has `suspended` flag set to `true`. This is enough to exclude provider from the extras of airflow and (automatically) from being used when CI image is build and constraints are being generated, as well as from provider documentation/generation. Also several parts of the CI build use the flag to filter out such suspended provider from: * verification of provider.yaml files in pre-commit is skipped in terms of importing and checking if classes are defined and listed in the provider.yaml * the "tests" folders for providers are skipped automatically if the provider has "suspend" = true set * in case of PR that is aimed to modify suspended providers directory tree (when it is not a global provider refactor) selective checks will detect it and fail such PR with appropriate message suggesting to fix the reason for suspention first * documentation build is skipped for suspended providers * mypy static checks will skip suspended provider folders while we will still run ruff checks on them (unlike mypy ruff does not expect the libraries that it imports to be available and we are running ruff in a separate environment where no airflow dependencies are installed anyway
1 parent d8a3448 commit b44b5be

File tree

107 files changed

+626
-179
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+626
-179
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ jobs:
165165
docs-filter: ${{ steps.selective-checks.outputs.docs-filter }}
166166
skip-pre-commits: ${{ steps.selective-checks.outputs.skip-pre-commits }}
167167
debug-resources: ${{ steps.selective-checks.outputs.debug-resources }}
168+
suspended-providers-folders: ${{ steps.selective-checks.outputs.suspended-providers-folders }}
168169
source-head-repo: ${{ steps.source-run-info.outputs.source-head-repo }}
169170
pull-request-labels: ${{ steps.source-run-info.outputs.pr-labels }}
170171
in-workflow-build: ${{ steps.source-run-info.outputs.in-workflow-build }}
@@ -884,6 +885,7 @@ jobs:
884885
env:
885886
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
886887
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
888+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
887889
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
888890
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
889891
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
@@ -924,6 +926,7 @@ jobs:
924926
env:
925927
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
926928
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
929+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
927930
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
928931
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
929932
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
@@ -976,6 +979,7 @@ jobs:
976979
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
977980
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
978981
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
982+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
979983
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
980984
BACKEND: "mysql"
981985
PYTHON_MAJOR_MINOR_VERSION: "${{matrix.python-version}}"
@@ -1019,6 +1023,7 @@ jobs:
10191023
env:
10201024
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
10211025
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
1026+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
10221027
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
10231028
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
10241029
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
@@ -1061,6 +1066,7 @@ jobs:
10611066
env:
10621067
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
10631068
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
1069+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
10641070
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
10651071
PYTHON_MAJOR_MINOR_VERSION: "${{matrix.python-version}}"
10661072
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
@@ -1097,6 +1103,7 @@ jobs:
10971103
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
10981104
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
10991105
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
1106+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
11001107
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
11011108
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
11021109
BACKEND: "postgres"
@@ -1156,6 +1163,7 @@ jobs:
11561163
env:
11571164
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
11581165
PARALLEL_TEST_TYPES: "${{needs.build-info.output.parallel-test-types}}"
1166+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
11591167
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
11601168
FULL_TESTS_NEEDED: "${{needs.build-info.outputs.full-tests-needed}}"
11611169
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"
@@ -1197,6 +1205,7 @@ jobs:
11971205
env:
11981206
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
11991207
PARALLEL_TEST_TYPES: "Quarantined"
1208+
SUSPENDED_PROVIDERS_FOLDERS: "${{ needs.build-info.outputs.suspended-providers-folders }}"
12001209
PR_LABELS: "${{needs.build-info.outputs.pull-request-labels}}"
12011210
PYTHON_MAJOR_MINOR_VERSION: "${{needs.build-info.outputs.default-python-version}}"
12021211
DEBUG_RESOURCES: "${{needs.build-info.outputs.debug-resources}}"

.pre-commit-config.yaml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ repos:
321321
name: Checks setup extra packages
322322
description: Checks if all the libraries in setup.py are listed in extra-packages-ref.rst file
323323
language: python
324-
files: ^setup\.py$|^docs/apache-airflow/extra-packages-ref\.rst$
324+
files: ^setup\.py$|^docs/apache-airflow/extra-packages-ref\.rst$|^airflow/providers/.*/provider\.yaml$
325325
pass_filenames: false
326326
entry: ./scripts/ci/pre_commit/pre_commit_check_setup_extra_packages_ref.py
327327
additional_dependencies: ['rich>=12.4.4']
@@ -350,7 +350,7 @@ repos:
350350
name: Update extras in documentation
351351
entry: ./scripts/ci/pre_commit/pre_commit_insert_extras.py
352352
language: python
353-
files: ^setup\.py$|^CONTRIBUTING\.rst$|^INSTALL$
353+
files: ^setup\.py$|^CONTRIBUTING\.rst$|^INSTALL$|^airflow/providers/.*/provider\.yaml$
354354
pass_filenames: false
355355
additional_dependencies: ['rich>=12.4.4']
356356
- id: check-extras-order
@@ -698,7 +698,7 @@ repos:
698698
files: ^dev/breeze/.*$
699699
pass_filenames: false
700700
require_serial: true
701-
additional_dependencies: ['click', 'rich>=12.4.4']
701+
additional_dependencies: ['click', 'rich>=12.4.4', 'pyyaml']
702702
- id: check-system-tests-present
703703
name: Check if system tests have required segments of code
704704
entry: ./scripts/ci/pre_commit/pre_commit_check_system_tests.py
@@ -844,10 +844,15 @@ repos:
844844
name: Update output of breeze commands in BREEZE.rst
845845
entry: ./scripts/ci/pre_commit/pre_commit_breeze_cmd_line.py
846846
language: python
847-
files: ^BREEZE\.rst$|^dev/breeze/.*$|^\.pre-commit-config\.yaml$
847+
files: >
848+
(?x)
849+
^BREEZE\.rst$|^dev/breeze/.*$|
850+
^\.pre-commit-config\.yaml$|
851+
^scripts/ci/pre_commit/pre_commit_breeze_cmd_line.py$|
852+
^generated/provider_dependencies.json$
848853
require_serial: true
849854
pass_filenames: false
850-
additional_dependencies: ['rich>=12.4.4', 'rich-click>=1.5', 'inputimeout']
855+
additional_dependencies: ['rich>=12.4.4', 'rich-click>=1.5', 'inputimeout', 'pyyaml']
851856
- id: check-example-dags-urls
852857
name: Check that example dags url include provider versions
853858
entry: ./scripts/ci/pre_commit/pre_commit_update_example_dags_paths.py
@@ -894,31 +899,31 @@ repos:
894899
entry: ./scripts/ci/pre_commit/pre_commit_mypy.py
895900
files: ^dev/.*\.py$
896901
require_serial: true
897-
additional_dependencies: ['rich>=12.4.4', 'inputimeout']
902+
additional_dependencies: ['rich>=12.4.4', 'inputimeout', 'pyyaml']
898903
- id: run-mypy
899904
name: Run mypy for core
900905
language: python
901906
entry: ./scripts/ci/pre_commit/pre_commit_mypy.py --namespace-packages
902907
files: \.py$
903908
exclude: ^.*/_vendor/|^airflow/migrations|^airflow/providers|^dev|^docs|^provider_packages|^tests/providers|^tests/system/providers
904909
require_serial: true
905-
additional_dependencies: ['rich>=12.4.4', 'inputimeout']
910+
additional_dependencies: ['rich>=12.4.4', 'inputimeout', 'pyyaml']
906911
- id: run-mypy
907912
name: Run mypy for providers
908913
language: python
909914
entry: ./scripts/ci/pre_commit/pre_commit_mypy.py --namespace-packages
910915
files: ^airflow/providers/.*\.py$|^tests/providers/\*\.py$|^tests/system/providers/\*\.py$
911916
exclude: ^.*/_vendor/
912917
require_serial: true
913-
additional_dependencies: ['rich>=12.4.4', 'inputimeout']
918+
additional_dependencies: ['rich>=12.4.4', 'inputimeout', 'pyyaml']
914919
- id: run-mypy
915920
name: Run mypy for /docs/ folder
916921
language: python
917922
entry: ./scripts/ci/pre_commit/pre_commit_mypy.py
918923
files: ^docs/.*\.py$
919924
exclude: ^docs/rtd-deprecation
920925
require_serial: true
921-
additional_dependencies: ['rich>=12.4.4', 'inputimeout']
926+
additional_dependencies: ['rich>=12.4.4', 'inputimeout', 'pyyaml']
922927
- id: check-provider-yaml-valid
923928
name: Validate provider.yaml files
924929
entry: ./scripts/ci/pre_commit/pre_commit_check_provider_yaml_files.py

Dockerfile.ci

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,17 @@ EXTRA_PYTEST_ARGS=(
890890
"-rfEX"
891891
)
892892

893+
if [[ ${SUSPENDED_PROVIDERS_FOLDERS=} != "" ]]; then
894+
for provider in ${SUSPENDED_PROVIDERS_FOLDERS=}; do
895+
echo "Skipping tests for suspended provider: ${provider}"
896+
EXTRA_PYTEST_ARGS+=(
897+
"--ignore=tests/providers/${provider}"
898+
"--ignore=tests/system/providers/${provider}"
899+
"--ignore=tests/integration/providers/${provider}"
900+
)
901+
done
902+
fi
903+
893904
if [[ "${TEST_TYPE}" == "Helm" ]]; then
894905
_cpus="$(grep -c 'cpu[0-9]' /proc/stat)"
895906
echo "Running tests with ${_cpus} CPUs in parallel"

airflow/provider.yaml.schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
"type": "string"
2222
}
2323
},
24+
"suspended": {
25+
"description": "If set to true, the provider is suspended and it's not a candidate for release nor contributes dependencies to constraint calculations/CI image. Tests are excluded.",
26+
"type:": "boolean"
27+
},
2428
"dependencies": {
2529
"description": "Dependencies that should be added to the provider",
2630
"type": "array",
@@ -326,6 +330,7 @@
326330
"name",
327331
"package-name",
328332
"description",
333+
"suspended",
329334
"dependencies",
330335
"versions"
331336
]
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
.. Licensed to the Apache Software Foundation (ASF) under one
2+
or more contributor license agreements. See the NOTICE file
3+
distributed with this work for additional information
4+
regarding copyright ownership. The ASF licenses this file
5+
to you under the Apache License, Version 2.0 (the
6+
"License"); you may not use this file except in compliance
7+
with the License. You may obtain a copy of the License at
8+
9+
.. http://www.apache.org/licenses/LICENSE-2.0
10+
11+
.. Unless required by applicable law or agreed to in writing,
12+
software distributed under the License is distributed on an
13+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
KIND, either express or implied. See the License for the
15+
specific language governing permissions and limitations
16+
under the License.
17+
18+
Suspending providers
19+
====================
20+
21+
As of April 2023, we have the possibility to suspend individual providers, so that they are not holding
22+
back dependencies for Airflow and other providers. The process of suspending providers is described
23+
in `description of the process <https://github.com/apache/airflow/blob/main/README.md#suspending-releases-for-providers>`_
24+
25+
Technically, suspending a provider is done by setting ``suspended : true``, in the provider.yaml of the
26+
provider. This should be followed by committing the change and either automatically or manually running
27+
pre-commit checks that will either update derived configuration files or ask you to update them manually.
28+
Note that you might need to run pre-commit several times until all the static checks pass,
29+
because modification from one pre-commit might impact other pre-commits.
30+
31+
If you have pre-commit installed, pre-commit will be run automatically on commit. If you want to run it
32+
manually after commit, you can run it via ``breeze static-checks --last-commit`` some of the tests might fail
33+
because suspension of the provider might cause changes in the dependencies, so if you see errors about
34+
missing dependencies imports, non-usable classes etc., you will need to build the CI image locally
35+
via ``breeze build-image --python 3.7 --upgrade-to-newer-dependencies`` after the first pre-commit run
36+
and then run the static checks again.
37+
38+
If you want to be absolutely sure to run all static checks you can always do this via
39+
``pre-commit run --all-files`` or ``breeze static-checks --all-files``.
40+
41+
Some of the manual modifications you will have to do (in both cases ``pre-commit`` will guide you on what
42+
to do.
43+
44+
* You will have to run ``breeze setup regenerate-command-images`` to regenerate breeze help files
45+
* you will need to update ``extra-packages-ref.rst`` and in some cases - when mentioned there explicitly -
46+
``setup.py`` to remove the provider from list of dependencies.
47+
48+
What happens under-the-hood as the result, is that ``generated/providers.json`` file is updated with
49+
the information about available providers and their dependencies and it is used by our tooling to
50+
exclude suspended providers from all relevant parts of the build and CI system (such as building CI image
51+
with dependencies, building documentation, running tests, etc.)
52+
53+
54+
Additional changes needed for cross-dependent providers
55+
=======================================================
56+
57+
Those steps above are usually enough for most providers that are "standalone" and not imported or used by
58+
other providers (in most cases we will not suspend such providers). However some extra steps might be needed
59+
for providers that are used by other providers, or that are part of the default PROD Dockerfile:
60+
61+
* Most of the tests for the suspended provider, will be automatically excluded by pytest collection. However,
62+
in case a provider is dependent on by another provider, the relevant tests might fail to be collected or
63+
run by ``pytest``. In such cases you should skip the whole test module failing to be collected by
64+
adding ``pytest.importorskip`` at the top of the test module.
65+
For example if your tests fail because they need to import ``apache.airflow.providers.google``
66+
and you have suspended it, you should add this line at the top of the test module that fails.
67+
68+
Example failing collection after ``google`` provider has been suspended:
69+
70+
.. code-block:: txt
71+
72+
_____ ERROR collecting tests/providers/apache/beam/operators/test_beam.py ______
73+
ImportError while importing test module '/opt/airflow/tests/providers/apache/beam/operators/test_beam.py'.
74+
Hint: make sure your test modules/packages have valid Python names.
75+
Traceback:
76+
/usr/local/lib/python3.7/importlib/__init__.py:127: in import_module
77+
return _bootstrap._gcd_import(name[level:], package, level)
78+
tests/providers/apache/beam/operators/test_beam.py:25: in <module>
79+
from airflow.providers.apache.beam.operators.beam import (
80+
airflow/providers/apache/beam/operators/beam.py:35: in <module>
81+
from airflow.providers.google.cloud.hooks.dataflow import (
82+
airflow/providers/google/cloud/hooks/dataflow.py:32: in <module>
83+
from google.cloud.dataflow_v1beta3 import GetJobRequest, Job, JobState, JobsV1Beta3AsyncClient, JobView
84+
E ModuleNotFoundError: No module named 'google.cloud.dataflow_v1beta3'
85+
_ ERROR collecting tests/providers/microsoft/azure/transfers/test_azure_blob_to_gcs.py _
86+
87+
88+
The fix is to add this line at the top of the ``tests/providers/apache/beam/operators/test_beam.py`` module:
89+
90+
.. code-block:: python
91+
92+
pytest.importorskip("apache.airflow.providers.google")
93+
94+
95+
* Some of the other providers might also just import unconditionally the suspended provider and they will
96+
fail during provider verification step in CI. In this case you should turn the provider imports
97+
into conditional imports. For example when import fails after ``amazon`` provider has been suspended:
98+
99+
.. code-block:: txt
100+
101+
Traceback (most recent call last):
102+
File "/opt/airflow/scripts/in_container/verify_providers.py", line 266, in import_all_classes
103+
_module = importlib.import_module(modinfo.name)
104+
File "/usr/local/lib/python3.7/importlib/__init__.py", line 127, in import_module
105+
return _bootstrap._gcd_import(name, package, level)
106+
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
107+
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
108+
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
109+
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
110+
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
111+
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
112+
File "/usr/local/lib/python3.7/site-packages/airflow/providers/mysql/transfers/s3_to_mysql.py", line 23, in <module>
113+
from airflow.providers.amazon.aws.hooks.s3 import S3Hook
114+
ModuleNotFoundError: No module named 'airflow.providers.amazon'
115+
116+
or:
117+
118+
.. code-block:: txt
119+
120+
Error: The ``airflow.providers.microsoft.azure.transfers.azure_blob_to_gcs`` object in transfers list in
121+
airflow/providers/microsoft/azure/provider.yaml does not exist or is not a module:
122+
No module named 'gcloud.aio.storage'
123+
124+
The fix for that is to turn the feature into an optional provider feature (in the place where the excluded
125+
``airflow.providers`` import happens:
126+
127+
.. code-block:: python
128+
129+
try:
130+
from airflow.providers.amazon.aws.hooks.s3 import S3Hook
131+
except ImportError as e:
132+
from airflow.exceptions import AirflowOptionalProviderFeatureException
133+
134+
raise AirflowOptionalProviderFeatureException(e)
135+
136+
137+
* In case we suspend an important provider, which is part of the default Dockerfile you might want to
138+
update the tests for PROD docker image in ``docker_tests/test_prod_image.py``.
139+
140+
* Some of the suspended providers might also fail ``breeze`` unit tests that expect a fixed set of providers.
141+
Those tests should be adjusted (but this is not very likely to happen, because the tests are using only
142+
the most common providers that we will not be likely to suspend).
143+
144+
145+
Resuming providers
146+
==================
147+
148+
Resuming providers is done by reverting the original change that suspended it. In case there are changes
149+
needed to fix problems in the reverted provider, our CI will detect them and you will have to fix them
150+
as part of the PR reverting the suspension.

airflow/providers/airbyte/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Airbyte
2121
description: |
2222
`Airbyte <https://airbyte.io/>`__
2323
24+
suspended: false
2425
versions:
2526
- 3.2.1
2627
- 3.2.0

airflow/providers/alibaba/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Alibaba
2121
description: |
2222
Alibaba Cloud integration (including `Alibaba Cloud <https://www.alibabacloud.com//>`__).
2323
24+
suspended: false
2425
versions:
2526
- 2.3.0
2627
- 2.2.0

airflow/providers/amazon/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Amazon
2121
description: |
2222
Amazon integration (including `Amazon Web Services (AWS) <https://aws.amazon.com/>`__).
2323
24+
suspended: false
2425
versions:
2526
- 7.4.0
2627
- 7.3.0

airflow/providers/apache/beam/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Apache Beam
2121
description: |
2222
`Apache Beam <https://beam.apache.org/>`__.
2323
24+
suspended: false
2425
versions:
2526
- 4.3.0
2627
- 4.2.0

airflow/providers/apache/cassandra/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Apache Cassandra
2121
description: |
2222
`Apache Cassandra <http://cassandra.apache.org/>`__.
2323
24+
suspended: false
2425
versions:
2526
- 3.1.1
2627
- 3.1.0

airflow/providers/apache/drill/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Apache Drill
2121
description: |
2222
`Apache Drill <https://drill.apache.org/>`__.
2323
24+
suspended: false
2425
versions:
2526
- 2.3.2
2627
- 2.3.1

airflow/providers/apache/druid/provider.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ name: Apache Druid
2121
description: |
2222
`Apache Druid <https://druid.apache.org/>`__.
2323
24+
suspended: false
2425
versions:
2526
- 3.3.1
2627
- 3.3.0

0 commit comments

Comments
 (0)