Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/sc/branching/branching.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
from .commands.clean import Clean
from .commands.command import Command
from .commands.finish import Finish, FinishOperationError
from .commands.group import GroupShow
from .commands.init import Init
from .commands.list import List
from .commands.pull import Pull
from .commands.push import Push
from .commands.show import ShowBranch, ShowLog, ShowRepoFlowConfig
from .commands.start import Start
from .commands.status import Status
from .commands.tag import TagCheck, TagCreate, TagList, TagPush, TagRm, TagShow
Expand Down Expand Up @@ -198,6 +200,38 @@ def tag_check(tag: str, run_dir: Path = Path.cwd()):
project_type
)

@staticmethod
def show_branch(run_dir: Path = Path.cwd()):
top_dir, project_type = detect_project(run_dir)
run_command_by_project_type(
ShowBranch(top_dir),
project_type
)

@staticmethod
def show_repo_flow_config(run_dir: Path = Path.cwd()):
top_dir, project_type = detect_project(run_dir)
run_command_by_project_type(
ShowRepoFlowConfig(top_dir),
project_type
)

@staticmethod
def show_log(run_dir: Path = Path.cwd()):
top_dir, project_type = detect_project(run_dir)
run_command_by_project_type(
ShowLog(top_dir),
project_type
)

@staticmethod
def group_show(group: str | None, run_dir: Path = Path.cwd()):
top_dir, project_type = detect_project(run_dir)
run_command_by_project_type(
GroupShow(top_dir, group),
project_type
)


def detect_project(run_dir: Path) -> tuple[Path | ProjectType]:
if root := RepoLibrary.get_repo_root_dir(run_dir):
Expand Down
2 changes: 1 addition & 1 deletion src/sc/branching/commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ def get_alt_branch_name(branch: Branch, project: ProjectElementInterface) -> str
return None

def resolve_project_branch_name(branch: Branch, project: ProjectElementInterface) -> str:
return get_alt_branch_name(branch, project) or branch.name
return get_alt_branch_name(branch, project) or branch.name
94 changes: 94 additions & 0 deletions src/sc/branching/commands/group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright 2025 RDK Management
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for `sc group` functionality."""

from dataclasses import dataclass
import logging
import subprocess

from git import Repo
from sc_manifest_parser import ProjectElementInterface, ScManifest

from .command import Command

logger = logging.getLogger(__name__)

@dataclass
class GroupShow(Command):
"""List groups or show information about a particular group."""
group: str | None

def run_git_command(self):
logger.error("`sc show group` must be ran inside a repo project!")

def run_repo_command(self):
if self.group:
self._show_group_info()
else:
self._list_groups()

def _show_group_info(self):
manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
group_shown = False
for proj in manifest.projects:
project_groups = proj.groups
if not project_groups or self.group not in project_groups.split(","):
continue

group_shown = True
self._show_project(proj)
print()
logger.info("-" * 100)

if not group_shown:
logger.warning(f"No project matching group `{self.group}` found!")

def _list_groups(self):
manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
groups = []
for proj in manifest.projects:
project_groups = proj.groups
if project_groups:
groups.extend(project_groups.split(","))
groups = self._remove_duplicates(groups)
for group in groups:
logger.info(f"[{group}]")

def _remove_duplicates(self, target_list: list) -> list:
return(list(dict.fromkeys(target_list)))

def _show_project(self, proj: ProjectElementInterface):
"""Show information pertaining to a particular project."""
proj_dir = self.top_dir / proj.path
logger.info(f"Project: {proj_dir}")
logger.info(
f"Lock Status: [bold yellow]\[{proj.lock_status or 'NORMAL'}][/]",
extra={"markup": True}
)

repo = Repo(proj_dir)
if repo.remotes:
remote = repo.remotes[0]
url = next(remote.urls)
remote_status = f"{remote.name} {url}"
else:
remote_status = "No remotes configured"

logger.info(f"Remote Status: {remote_status}")

subprocess.run(
["git", "branch", "-vv", "--color=always"],
cwd=proj_dir,
check=False
)
122 changes: 122 additions & 0 deletions src/sc/branching/commands/show.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright 2025 RDK Management
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Commands to display information about a repo or sc project."""

from dataclasses import dataclass
import logging
from pathlib import Path
import subprocess

from git import Repo
from sc_manifest_parser import ProjectElementInterface, ScManifest

from .command import Command

logger = logging.getLogger(__name__)

@dataclass
class ShowBranch(Command):
"""Show branch information for all repositories."""
def run_git_command(self):
self._show_branch(self.top_dir)

def run_repo_command(self):
manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
for proj in manifest.projects:
self._show_project(proj)
print()
logger.info("-" * 100)

def _show_project(self, proj: ProjectElementInterface):
"""Show information pertaining to a particular project."""
proj_dir = self.top_dir / proj.path
logger.info(f"Project: {proj_dir}")
logger.info(
f"Lock Status: \[[bold yellow]{proj.lock_status or 'NORMAL'}[/]]",
extra={"markup": True}
)

if proj.groups:
groups = proj.groups.split(",")
group_str = " ".join([f"\[[bold yellow]{g}[/]]" for g in groups])
else:
group_str = "\[[red bold]No Groups[/]]"

logger.info(f"Groups: {group_str}", extra={"markup": True})

self._show_branch(proj_dir)

def _show_branch(self, repo_dir: Path):
"""Show remotes and branches of a git repo."""
repo = Repo(repo_dir)
if repo.remotes:
remote = repo.remotes[0]
url = next(remote.urls)
remote_status = f"{remote.name} {url}"
else:
remote_status = "No remotes configured"

logger.info(f"Remote Status: {remote_status}")

subprocess.run(
["git", "branch", "-vv", "--color=always"],
cwd=repo_dir,
check=False
)

@dataclass
class ShowRepoFlowConfig(Command):
"""Show git flow config for all projects."""
def run_git_command(self):
logger.error("`sc show repo_flow_config` must be ran inside a repo project!")

def run_repo_command(self):
manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
for proj in manifest.projects:
proj_dir = self.top_dir / proj.path
logger.info(f"Repo Flow Config: {proj_dir}")
result = subprocess.run(
["git", "config", "--list"],
cwd=proj_dir,
capture_output=True,
text=True,
check=False
)

for line in result.stdout.splitlines():
if "gitflow" in line:
print(line)

print()
logger.info("-" * 100)

@dataclass
class ShowLog(Command):
"""Display most recent commit on all repositories."""
def run_git_command(self):
self._show_log(self.top_dir)

def run_repo_command(self):
manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
for proj in manifest.projects:
logger.info(f"Project: {self.top_dir / proj.path}")
self._show_log(self.top_dir / proj.path)
logger.info("-" * 100)

def _show_log(self, repo_dir: Path):
subprocess.run(
["git", "log", "--pretty=oneline", "-n1"],
cwd=repo_dir,
check=False
)
2 changes: 1 addition & 1 deletion src/sc/branching/commands/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def run_git_command(self):
self._list_tags(self.top_dir)

def run_repo_command(self):
logger.info(f"Tags in mainfest: {self.top_dir / '.repo' / 'manifests'}")
logger.info(f"Tags in manifest: {self.top_dir / '.repo' / 'manifests'}")
self._list_tags(self.top_dir / '.repo' / 'manifests')

def _list_tags(self, repo_path: Path):
Expand Down
36 changes: 36 additions & 0 deletions src/sc/branching_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,5 +335,41 @@ def check(tag):
"""Check if a tag exists on all non READ_ONLY repos."""
SCBranching.tag_check(tag)

@cli.group()
def show():
"""sc show commands."""
pass

@show.command()
def branch():
"""Show the current status of branching."""
SCBranching.show_branch()

@show.command()
def repo_flow_config():
"""Show git flow config for all projects."""
SCBranching.show_repo_flow_config()

@show.command()
def log():
SCBranching.show_log()

@show.command()
@click.argument("tag")
def tag(tag):
"""Show information about a tag."""
SCBranching.tag_show(tag)

@show.command()
def tags():
"""List tags on the manifest."""
SCBranching.tag_list()

@show.command()
@click.argument("group", required=False)
def group(group):
"""List groups or show information about a group."""
SCBranching.group_show(group)

if __name__ == '__main__':
cli()