Repository: apache/airflow

Issue:
Dag disappears when DAG tag is longer than 100 char limit
### Apache Airflow version

2.2.5

### What happened

We added new DAG tags to a couple of our DAGs. In the case when the tag was longer than the 100 character limit the DAG was not showing in the UI and wasn't scheduled. It was however possible to reach it by typing in the URL to the DAG.
Usually when DAGs are broken there will be an error message in the UI, but this problem did not render any error message.

This problem occurred to one of our templated DAGs. Only one DAG broke and it was the one with a DAG tag which was too long. When we fixed the length, the DAG was scheduled and was visible in the UI again.

### What you think should happen instead

Exclude the dag if it is over the 100 character limit or show an error message in the UI.

### How to reproduce

Add a DAG tag which is longer than 100 characters.

### Operating System

Ubuntu

### Versions of Apache Airflow Providers

_No response_

### Deployment

Other 3rd-party Helm chart

### Deployment details

Running Airflow in Kubernetes.
Syncing DAGs from S3 with https://tech.scribd.com/blog/2020/breaking-up-the-dag-repo.html

### Anything else

_No response_

### Are you willing to submit PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)



Discussion:
Interesting :)
Hi! I'll pick up this good-first-issue!
Assigned you :)
@potiuk
I think we'll just add a length check to [tags](https://github.com/apache/airflow/blob/main/airflow/models/dag.py#L345).
If we have a tag with length >= 100, we raise an exception.

But I'm not sure how we pip install the dependencies. I [read](https://github.com/apache/airflow/blob/main/LOCAL_VIRTUALENV.rst#creating-a-local-virtualenv) that only `pip` installation is officially supported.

I wonder if [dev/requirements.txt](https://github.com/apache/airflow/blob/main/dev/requirements.txt) & [docker_test/requirements.txt](https://github.com/apache/airflow/blob/main/docker_tests/requirements.txt) are all the requirements.txt that can get us to run unit tests? Thanks a lot!
@TommyDew42 -> https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst has all the instruction on starting contribution and links to how to setup development environments 

Resolving patch:
diff --git a/airflow/models/dag.py b/airflow/models/dag.py
--- a/airflow/models/dag.py
+++ b/airflow/models/dag.py
@@ -104,6 +104,7 @@
 DEFAULT_VIEW_PRESETS = ['grid', 'graph', 'duration', 'gantt', 'landing_times']
 ORIENTATION_PRESETS = ['LR', 'TB', 'RL', 'BT']
 
+TAG_MAX_LEN = 100
 
 DagStateChangeCallback = Callable[[Context], None]
 ScheduleInterval = Union[None, str, timedelta, relativedelta]
@@ -374,6 +375,9 @@ def __init__(
     ):
         from airflow.utils.task_group import TaskGroup
 
+        if tags and any(len(tag) > TAG_MAX_LEN for tag in tags):
+            raise AirflowException(f"tag cannot be longer than {TAG_MAX_LEN} characters")
+
         self.user_defined_macros = user_defined_macros
         self.user_defined_filters = user_defined_filters
         if default_args and not isinstance(default_args, dict):
@@ -2782,7 +2786,7 @@ class DagTag(Base):
     """A tag name per dag, to allow quick filtering in the DAG view."""
 
     __tablename__ = "dag_tag"
-    name = Column(String(100), primary_key=True)
+    name = Column(String(TAG_MAX_LEN), primary_key=True)
     dag_id = Column(
         String(ID_LEN),
         ForeignKey('dag.dag_id', name='dag_tag_dag_id_fkey', ondelete='CASCADE'),


Test patch:
diff --git a/tests/models/test_dag.py b/tests/models/test_dag.py
--- a/tests/models/test_dag.py
+++ b/tests/models/test_dag.py
@@ -2585,6 +2585,24 @@ def test__time_restriction(dag_maker, dag_date, tasks_date, restrict):
     assert dag._time_restriction == restrict
 
 
+@pytest.mark.parametrize(
+    'tags, should_pass',
+    [
+        pytest.param([], True, id="empty tags"),
+        pytest.param(['a normal tag'], True, id="one tag"),
+        pytest.param(['a normal tag', 'another normal tag'], True, id="two tags"),
+        pytest.param(['a' * 100], True, id="a tag that's of just length 100"),
+        pytest.param(['a normal tag', 'a' * 101], False, id="two tags and one of them is of length > 100"),
+    ],
+)
+def test__tags_length(tags: List[str], should_pass: bool):
+    if should_pass:
+        models.DAG('test-dag', tags=tags)
+    else:
+        with pytest.raises(AirflowException):
+            models.DAG('test-dag', tags=tags)
+
+
 @pytest.fixture()
 def reset_dataset():
     clear_db_datasets()