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
15 changes: 15 additions & 0 deletions src/sc/branching/branching.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from .commands.checkout import Checkout
from .commands.clean import Clean
from .commands.command import Command
from .commands.delete import Delete
from .commands.finish import Finish
from .commands.group import (GroupCheckout, GroupCmd, GroupFetch, GroupPush, GroupPull,
GroupShow, GroupTag)
Expand Down Expand Up @@ -85,6 +86,20 @@ def checkout(
Checkout(top_dir, branch, force=force, verify=verify),
project_type
)

@staticmethod
def delete(
branch_type: BranchType,
name: str | None = None,
remote: bool = False,
run_dir: Path = Path.cwd()
):
top_dir, project_type = detect_project(run_dir)
branch = create_branch(project_type, top_dir, branch_type, name)
run_command_by_project_type(
Delete(top_dir, branch, remote),
project_type
)

@staticmethod
def status(
Expand Down
58 changes: 58 additions & 0 deletions src/sc/branching/commands/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 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.
from dataclasses import dataclass
import logging
from pathlib import Path

from git import Repo
from git_flow_library import GitFlowLibrary
from sc_manifest_parser import ScManifest

from ..branch import Branch
from .command import Command

logger = logging.getLogger(__name__)

@dataclass
class Delete(Command):
branch: Branch
remote: bool = False

def run_git_command(self):
self._delete_branch(self.top_dir)

def run_repo_command(self):
self._error_on_sc_uninitialised()
if self.remote:
logger.info(f"Removing Local & Remote Branch {self.branch.name}")
else:
logger.info(f"Removing Local Branch {self.branch.name}")

manifest = ScManifest.from_repo_root(self.top_dir / '.repo')
for proj in manifest.projects:
if proj.lock_status == None:
self._delete_branch(self.top_dir / proj.path, proj.remote)

self._delete_branch(self.top_dir / '.repo' / 'manifests')

def _delete_branch(self, dir: Path, remote_name: str | None = None):
repo = Repo(dir)
if repo.active_branch.name == self.branch.name:
repo.git.switch(GitFlowLibrary.get_develop_branch(dir))
repo.git.branch("-D", self.branch.name)
if self.remote:
if not remote_name:
remote_name = repo.remotes[0].name
repo.git.push(remote_name, f":{self.branch.name}")
Comment thread
TB-1993 marked this conversation as resolved.
repo.git.update_ref("-d", f"refs/remotes/m/{self.branch.name}")
Comment on lines +54 to +58
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It says this but it worked on old sc and works in the tests with different remote names?

21 changes: 21 additions & 0 deletions src/sc/branching_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ def list():
"""List feature branches."""
SCBranching.list(BranchType.FEATURE)

@feature.command()
@click.argument('name', required=False)
@click.option("-r", "--remote", is_flag=True, help="Delete remote branches.")
def delete(name, remote):
"""Delete feature branch."""
SCBranching.delete(BranchType.FEATURE, name, remote)

# Develop branch commands
@cli.group()
def develop():
Expand Down Expand Up @@ -167,6 +174,13 @@ def list():
"""List release branches."""
SCBranching.list(BranchType.RELEASE)

@release.command()
@click.argument('name', required=False)
@click.option("-r", "--remote", is_flag=True, help="Delete remote branches.")
def delete(name, remote):
"""Delete release branch."""
SCBranching.delete(BranchType.RELEASE, name, remote)

# Hotfix branch commands
@cli.group()
def hotfix():
Expand Down Expand Up @@ -216,6 +230,13 @@ def list():
"""List hotfix branches."""
SCBranching.list(BranchType.HOTFIX)

@hotfix.command()
@click.argument('name', required=False)
@click.option("-r", "--remote", is_flag=True, help="Delete remote branches.")
def delete(name, remote):
"""Delete hotfix branch."""
SCBranching.delete(BranchType.HOTFIX, name, remote)

# Support branch commands
@cli.group()
def support():
Expand Down
95 changes: 95 additions & 0 deletions tests/branching/test_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 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.

import subprocess
import unittest

from git import Repo

from .repo_client_creator import RepoTestClientCreator

class TestDelete(unittest.TestCase):
def setUp(self):
self.repo_client = RepoTestClientCreator()

def tearDown(self):
self.repo_client.cleanup()

def test_feature_delete(self):
self.repo_client.add_branches(["master", "develop", "feature/donut"])
proj = self.repo_client.add_project()
top_dir = self.repo_client.create("feature/donut")

subprocess.run(["sc", "feature", "delete", "donut"], cwd=top_dir)

Comment thread
BenjiMilan marked this conversation as resolved.
proj_repo = Repo(top_dir / proj.name)
manifest_repo = Repo(top_dir / ".repo" / "manifests")
self.assertEqual(proj_repo.active_branch.name, "develop")
self.assertFalse("feature/donut" in [b.name for b in proj_repo.branches])
self.assertTrue(_remote_branch_exists(proj_repo, "feature/donut"))
self.assertEqual(manifest_repo.active_branch.name, "develop")
self.assertFalse("feature/donut" in [b.name for b in manifest_repo.branches])
self.assertTrue(_remote_branch_exists(manifest_repo, "feature/donut"))

def test_release_delete(self):
self.repo_client.add_branches(["master", "develop", "release/donut"])
proj = self.repo_client.add_project()
top_dir = self.repo_client.create("release/donut")

subprocess.run(["sc", "release", "delete", "donut"], cwd=top_dir)

Comment thread
BenjiMilan marked this conversation as resolved.
proj_repo = Repo(top_dir / proj.name)
manifest_repo = Repo(top_dir / ".repo" / "manifests")
self.assertEqual(proj_repo.active_branch.name, "develop")
self.assertFalse("release/donut" in [b.name for b in proj_repo.branches])
self.assertTrue(_remote_branch_exists(proj_repo, "release/donut"))
self.assertEqual(manifest_repo.active_branch.name, "develop")
self.assertFalse("release/donut" in [b.name for b in manifest_repo.branches])
self.assertTrue(_remote_branch_exists(manifest_repo, "release/donut"))

def test_hotfix_delete(self):
self.repo_client.add_branches(["master", "develop", "hotfix/donut"])
proj = self.repo_client.add_project()
top_dir = self.repo_client.create("hotfix/donut")

subprocess.run(["sc", "hotfix", "delete", "donut"], cwd=top_dir)

proj_repo = Repo(top_dir / proj.name)
manifest_repo = Repo(top_dir / ".repo" / "manifests")
self.assertEqual(proj_repo.active_branch.name, "develop")
self.assertFalse("hotfix/donut" in [b.name for b in proj_repo.branches])
self.assertTrue(_remote_branch_exists(proj_repo, "hotfix/donut"))
self.assertEqual(manifest_repo.active_branch.name, "develop")
self.assertFalse("hotfix/donut" in [b.name for b in manifest_repo.branches])
self.assertTrue(_remote_branch_exists(manifest_repo, "hotfix/donut"))

def test_feature_delete_remote(self):
self.repo_client.add_branches(["master", "develop", "feature/donut"])
proj = self.repo_client.add_project()
top_dir = self.repo_client.create("feature/donut")

subprocess.run(["sc", "feature", "delete", "donut", "-r"], cwd=top_dir)

proj_repo = Repo(top_dir / proj.name)
manifest_repo = Repo(top_dir / ".repo" / "manifests")
self.assertEqual(proj_repo.active_branch.name, "develop")
self.assertFalse("feature/donut" in [b.name for b in proj_repo.branches])
self.assertFalse(_remote_branch_exists(proj_repo, "feature/donut"))
self.assertEqual(manifest_repo.active_branch.name, "develop")
self.assertFalse("feature/donut" in [b.name for b in manifest_repo.branches])
self.assertFalse(_remote_branch_exists(manifest_repo, "feature/donut"))

def _remote_branch_exists(repo: Repo, branch: str) -> bool:
out = repo.git.ls_remote("--heads", repo.remotes[0].name, branch)
return bool(out.strip())
Loading