This is an automated email from the ASF dual-hosted git repository.

o-nikolas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 562d62e9355 add 'teams sync' cli command (#66418)
562d62e9355 is described below

commit 562d62e9355a1e8a6ba1d7ce334f373a862d2c64
Author: stephen-bracken <[email protected]>
AuthorDate: Tue May 12 23:47:48 2026 +0100

    add 'teams sync' cli command (#66418)
    
    Co-authored-by: Stephen Bracken <email-protected>
---
 airflow-core/src/airflow/cli/cli_config.py         |  7 ++++
 .../src/airflow/cli/commands/team_command.py       | 28 +++++++++++++++
 .../tests/unit/cli/commands/test_team_command.py   | 41 ++++++++++++++++++++++
 3 files changed, 76 insertions(+)

diff --git a/airflow-core/src/airflow/cli/cli_config.py 
b/airflow-core/src/airflow/cli/cli_config.py
index 990325de74b..4c44ab39d67 100644
--- a/airflow-core/src/airflow/cli/cli_config.py
+++ b/airflow-core/src/airflow/cli/cli_config.py
@@ -1523,6 +1523,13 @@ TEAMS_COMMANDS = (
         func=lazy_load_command("airflow.cli.commands.team_command.team_list"),
         args=(ARG_OUTPUT, ARG_VERBOSE),
     ),
+    ActionCommand(
+        name="sync",
+        help="Sync teams",
+        description=("Sync missing teams from the dag bundle config into the 
database.\n"),
+        func=lazy_load_command("airflow.cli.commands.team_command.team_sync"),
+        args=(ARG_VERBOSE,),
+    ),
 )
 DB_COMMANDS = (
     ActionCommand(
diff --git a/airflow-core/src/airflow/cli/commands/team_command.py 
b/airflow-core/src/airflow/cli/commands/team_command.py
index 13702d516c4..7928b3d716b 100644
--- a/airflow-core/src/airflow/cli/commands/team_command.py
+++ b/airflow-core/src/airflow/cli/commands/team_command.py
@@ -25,6 +25,7 @@ from sqlalchemy import func, select
 from sqlalchemy.exc import IntegrityError
 
 from airflow.cli.simple_table import AirflowConsole
+from airflow.dag_processing.bundles.manager import DagBundlesManager
 from airflow.models.connection import Connection
 from airflow.models.pool import Pool
 from airflow.models.team import Team, dag_bundle_team_association_table
@@ -155,3 +156,30 @@ def team_list(args, session=NEW_SESSION):
         print(NO_TEAMS_LIST_MSG)
     else:
         _show_teams(teams=teams, output=args.output)
+
+
+@cli_utils.action_cli
+@providers_configuration_loaded
+@provide_session
+def team_sync(args, session=NEW_SESSION):
+    """Sync missing teams from the dag bundle config."""
+    dag_bundle_teams = {
+        bundle.team_name
+        for bundle in DagBundlesManager()._bundle_config.values()
+        if bundle.team_name is not None
+    }
+
+    teams_added = 0
+
+    try:
+        for team_name in dag_bundle_teams - Team.get_all_team_names(session):
+            team = Team(name=team_name)
+            session.add(team)
+            teams_added += 1
+        session.commit()
+    except Exception as e:
+        session.rollback()
+        raise SystemExit(f"Failed to sync teams: {e}")
+
+    if teams_added > 0:
+        print(f"{teams_added} teams added.")
diff --git a/airflow-core/tests/unit/cli/commands/test_team_command.py 
b/airflow-core/tests/unit/cli/commands/test_team_command.py
index 55892489f8b..49ade1c19bc 100644
--- a/airflow-core/tests/unit/cli/commands/test_team_command.py
+++ b/airflow-core/tests/unit/cli/commands/test_team_command.py
@@ -17,6 +17,7 @@
 # under the License.
 from __future__ import annotations
 
+import json
 from unittest.mock import patch
 
 import pytest
@@ -30,6 +31,7 @@ from airflow.models.dagbundle import DagBundleModel
 from airflow.models.team import Team, dag_bundle_team_association_table
 from airflow.settings import Session
 
+from tests_common.test_utils.config import conf_vars
 from tests_common.test_utils.db import (
     clear_db_connections,
     clear_db_dag_bundles,
@@ -362,3 +364,42 @@ class TestCliTeams:
         assert "integration-1" in team_names
         assert "integration-2" not in team_names
         assert "integration-3" in team_names
+
+    def test_team_sync(self):
+        bundle_config = [
+            {
+                "name": "bundleone",
+                "classpath": 
"airflow.dag_processing.bundles.local.LocalDagBundle",
+                "kwargs": {"path": "/dev/null", "refresh_interval": 0},
+                "team_name": "team1",
+            },
+            {
+                "name": "bundletwo",
+                "classpath": 
"airflow.dag_processing.bundles.local.LocalDagBundle",
+                "kwargs": {"path": "/dev/null", "refresh_interval": 300},
+                "team_name": "team2",
+            },
+            {
+                "name": "bundlethree",
+                "classpath": 
"airflow.dag_processing.bundles.local.LocalDagBundle",
+                "kwargs": {"path": "/dev/null", "refresh_interval": 300},
+            },
+        ]
+
+        teams = self.session.scalars(select(Team)).all()
+        assert len(teams) == 0
+
+        with conf_vars(
+            {
+                ("core", "multi_team"): "True",
+                ("dag_processor", "dag_bundle_config_list"): 
json.dumps(bundle_config),
+            }
+        ):
+            team_command.team_sync(self.parser.parse_args(["teams", "sync"]))
+
+        teams = self.session.scalars(select(Team)).all()
+        assert len(teams) == 2
+
+        team_names = [team.name for team in teams]
+        assert "team1" in team_names
+        assert "team2" in team_names

Reply via email to