Skip to content

Strategies

Git workflow strategy implementations for PR management.

WorkflowStrategy

Bases: ABC

Base class for git workflow strategies.

Source code in src/codemap/git/pr_generator/strategies.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
class WorkflowStrategy(ABC):
	"""Base class for git workflow strategies."""

	@abstractmethod
	def get_default_base(self, branch_type: str) -> str | None:
		"""
		Get the default base branch for a given branch type.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)

		Returns:
		    Name of the default base branch

		"""
		raise NotImplementedError

	def suggest_branch_name(self, branch_type: str, description: str) -> str:
		"""
		Suggest a branch name based on the workflow.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)
		    description: Description of the branch

		Returns:
		    Suggested branch name

		"""
		clean_description = re.sub(r"[^a-zA-Z0-9]+", "-", description.lower()).strip("-")
		prefix = self.get_branch_prefix(branch_type)
		return f"{prefix}{clean_description}"

	@abstractmethod
	def get_branch_prefix(self, branch_type: str) -> str:
		"""
		Get the branch name prefix for a given branch type.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)

		Returns:
		    Branch name prefix

		"""
		raise NotImplementedError

	@abstractmethod
	def get_branch_types(self) -> list[str]:
		"""
		Get valid branch types for this workflow.

		Returns:
		    List of valid branch types

		"""
		raise NotImplementedError

	def detect_branch_type(self, branch_name: str | None) -> str | None:
		"""
		Detect the type of a branch from its name.

		Args:
		    branch_name: Name of the branch

		Returns:
		    Branch type or None if not detected

		"""
		for branch_type in self.get_branch_types():
			prefix = self.get_branch_prefix(branch_type)
			if branch_name and branch_name.startswith(prefix):
				return branch_type
		return None

	def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
		"""
		Get PR title and description templates for a given branch type.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)

		Returns:
		    Dictionary with 'title' and 'description' templates

		"""
		return DEFAULT_PR_TEMPLATE

	def get_remote_branches(self) -> list[str]:
		"""
		Get list of remote branches.

		Returns:
		    List of remote branch names (without 'origin/' prefix typically)

		"""
		try:
			pgu = PRGitUtils.get_instance()
			remote_branches = []
			for b_name in pgu.repo.branches.remote:
				if b_name.startswith("origin/"):
					branch_name_without_prefix = b_name[len("origin/") :]
					if not branch_name_without_prefix.startswith("HEAD"):
						remote_branches.append(branch_name_without_prefix)
				elif "/" in b_name and not b_name.endswith("/HEAD"):
					parts = b_name.split("/", 1)
					if len(parts) > 1:
						remote_branches.append(parts[1])
			return list(set(remote_branches))
		except (GitError, Pygit2GitError) as e:
			PRGitUtils.logger.debug(f"Error getting remote branches: {e}")
			return []
		except Exception as e:  # noqa: BLE001
			PRGitUtils.logger.debug(f"Unexpected error getting remote branches: {e}")
			return []

	def get_local_branches(self) -> list[str]:
		"""
		Get list of local branches.

		Returns:
		    List of local branch names

		"""
		try:
			pgu = PRGitUtils.get_instance()
			return list(pgu.repo.branches.local)
		except (GitError, Pygit2GitError) as e:
			PRGitUtils.logger.debug(f"Error getting local branches: {e}")
			return []
		except Exception as e:  # noqa: BLE001
			PRGitUtils.logger.debug(f"Unexpected error getting local branches: {e}")
			return []

	def get_branches_by_type(self) -> dict[str, list[str]]:
		"""
		Group branches by their type.

		Returns:
		    Dictionary mapping branch types to lists of branch names

		"""
		result = {branch_type: [] for branch_type in self.get_branch_types()}
		result["other"] = []  # For branches that don't match any type

		# Get all branches (local and remote)
		all_branches = set(self.get_local_branches() + self.get_remote_branches())

		for branch in all_branches:
			branch_type = self.detect_branch_type(branch)
			if branch_type:
				result[branch_type].append(branch)
			else:
				result["other"].append(branch)

		return result

	def get_branch_metadata(self, branch_name: str) -> dict[str, Any]:
		"""
		Get metadata for a specific branch.

		Args:
		    branch_name: Name of the branch

		Returns:
		    Dictionary with branch metadata

		"""
		try:
			pgu = PRGitUtils.get_instance()
			repo = pgu.repo

			# Determine full ref for revparse_single (try local, then remote)
			branch_ref_to_parse = branch_name
			if not branch_exists(branch_name, pgu_instance=pgu, include_remote=False) and branch_exists(
				branch_name, pgu_instance=pgu, remote_name="origin", include_local=False
			):
				branch_ref_to_parse = f"origin/{branch_name}"
			# If still not found by branch_exists, revparse_single might fail, which is caught below.

			last_commit_iso_date = "unknown"
			try:
				commit_obj = repo.revparse_single(branch_ref_to_parse).peel(Commit)
				commit_time = datetime.fromtimestamp(commit_obj.commit_time, tz=UTC)
				last_commit_iso_date = commit_time.isoformat()
			except (Pygit2GitError, GitError) as e:  # Catch errors resolving commit
				PRGitUtils.logger.debug(f"Could not get last commit date for {branch_ref_to_parse}: {e}")

			commit_count_str = "0"
			try:
				default_b = get_default_branch(pgu_instance=pgu)
				if default_b:
					# get_branch_relation expects full ref names or resolvable names
					_, count = pgu.get_branch_relation(default_b, branch_ref_to_parse)
					commit_count_str = str(count)
			except (GitError, Pygit2GitError) as e:
				PRGitUtils.logger.debug(f"Could not get commit count for {branch_ref_to_parse} vs default: {e}")

			branch_type_detected = self.detect_branch_type(branch_name)

			return {
				"last_commit_date": last_commit_iso_date,
				"commit_count": commit_count_str,
				"branch_type": branch_type_detected,
				"is_local": branch_exists(branch_name, pgu_instance=pgu, include_remote=False, include_local=True),
				"is_remote": branch_exists(branch_name, pgu_instance=pgu, remote_name="origin", include_local=False),
			}
		except (GitError, Pygit2GitError) as e:
			PRGitUtils.logger.warning(f"Error getting branch metadata for {branch_name}: {e}")
			return {  # Fallback for broader errors during pgu instantiation or initial checks
				"last_commit_date": "unknown",
				"commit_count": "0",
				"branch_type": self.detect_branch_type(branch_name),
				"is_local": False,
				"is_remote": False,
			}
		except Exception as e:  # noqa: BLE001
			PRGitUtils.logger.warning(f"Unexpected error getting branch metadata for {branch_name}: {e}")
			return {
				"last_commit_date": "unknown",
				"commit_count": "0",
				"branch_type": self.detect_branch_type(branch_name),
				"is_local": False,
				"is_remote": False,
			}

	def get_all_branches_with_metadata(self) -> dict[str, dict[str, Any]]:
		"""
		Get all branches with metadata.

		Returns:
		    Dictionary mapping branch names to metadata dictionaries

		"""
		result = {}
		# Using PRGitUtils for a consistent list of branches
		pgu = PRGitUtils.get_instance()
		local_b = list(pgu.repo.branches.local)
		remote_b_parsed = []
		for rb_name in pgu.repo.branches.remote:
			if rb_name.startswith("origin/") and not rb_name.endswith("/HEAD"):
				remote_b_parsed.append(rb_name[len("origin/") :])
			elif "/" in rb_name and not rb_name.endswith("/HEAD"):
				parts = rb_name.split("/", 1)
				if len(parts) > 1:
					remote_b_parsed.append(parts[1])

		all_branches = set(local_b + remote_b_parsed)

		for branch in all_branches:
			result[branch] = self.get_branch_metadata(branch)

		return result

get_default_base abstractmethod

get_default_base(branch_type: str) -> str | None

Get the default base branch for a given branch type.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required

Returns:

Type Description
str | None

Name of the default base branch

Source code in src/codemap/git/pr_generator/strategies.py
28
29
30
31
32
33
34
35
36
37
38
39
40
@abstractmethod
def get_default_base(self, branch_type: str) -> str | None:
	"""
	Get the default base branch for a given branch type.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)

	Returns:
	    Name of the default base branch

	"""
	raise NotImplementedError

suggest_branch_name

suggest_branch_name(
	branch_type: str, description: str
) -> str

Suggest a branch name based on the workflow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required
description str

Description of the branch

required

Returns:

Type Description
str

Suggested branch name

Source code in src/codemap/git/pr_generator/strategies.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def suggest_branch_name(self, branch_type: str, description: str) -> str:
	"""
	Suggest a branch name based on the workflow.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)
	    description: Description of the branch

	Returns:
	    Suggested branch name

	"""
	clean_description = re.sub(r"[^a-zA-Z0-9]+", "-", description.lower()).strip("-")
	prefix = self.get_branch_prefix(branch_type)
	return f"{prefix}{clean_description}"

get_branch_prefix abstractmethod

get_branch_prefix(branch_type: str) -> str

Get the branch name prefix for a given branch type.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required

Returns:

Type Description
str

Branch name prefix

Source code in src/codemap/git/pr_generator/strategies.py
58
59
60
61
62
63
64
65
66
67
68
69
70
@abstractmethod
def get_branch_prefix(self, branch_type: str) -> str:
	"""
	Get the branch name prefix for a given branch type.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)

	Returns:
	    Branch name prefix

	"""
	raise NotImplementedError

get_branch_types abstractmethod

get_branch_types() -> list[str]

Get valid branch types for this workflow.

Returns:

Type Description
list[str]

List of valid branch types

Source code in src/codemap/git/pr_generator/strategies.py
72
73
74
75
76
77
78
79
80
81
@abstractmethod
def get_branch_types(self) -> list[str]:
	"""
	Get valid branch types for this workflow.

	Returns:
	    List of valid branch types

	"""
	raise NotImplementedError

detect_branch_type

detect_branch_type(branch_name: str | None) -> str | None

Detect the type of a branch from its name.

Parameters:

Name Type Description Default
branch_name str | None

Name of the branch

required

Returns:

Type Description
str | None

Branch type or None if not detected

Source code in src/codemap/git/pr_generator/strategies.py
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def detect_branch_type(self, branch_name: str | None) -> str | None:
	"""
	Detect the type of a branch from its name.

	Args:
	    branch_name: Name of the branch

	Returns:
	    Branch type or None if not detected

	"""
	for branch_type in self.get_branch_types():
		prefix = self.get_branch_prefix(branch_type)
		if branch_name and branch_name.startswith(prefix):
			return branch_type
	return None

get_pr_templates

get_pr_templates(branch_type: str) -> dict[str, str]

Get PR title and description templates for a given branch type.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required

Returns:

Type Description
dict[str, str]

Dictionary with 'title' and 'description' templates

Source code in src/codemap/git/pr_generator/strategies.py
100
101
102
103
104
105
106
107
108
109
110
111
def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
	"""
	Get PR title and description templates for a given branch type.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)

	Returns:
	    Dictionary with 'title' and 'description' templates

	"""
	return DEFAULT_PR_TEMPLATE

get_remote_branches

get_remote_branches() -> list[str]

Get list of remote branches.

Returns:

Type Description
list[str]

List of remote branch names (without 'origin/' prefix typically)

Source code in src/codemap/git/pr_generator/strategies.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def get_remote_branches(self) -> list[str]:
	"""
	Get list of remote branches.

	Returns:
	    List of remote branch names (without 'origin/' prefix typically)

	"""
	try:
		pgu = PRGitUtils.get_instance()
		remote_branches = []
		for b_name in pgu.repo.branches.remote:
			if b_name.startswith("origin/"):
				branch_name_without_prefix = b_name[len("origin/") :]
				if not branch_name_without_prefix.startswith("HEAD"):
					remote_branches.append(branch_name_without_prefix)
			elif "/" in b_name and not b_name.endswith("/HEAD"):
				parts = b_name.split("/", 1)
				if len(parts) > 1:
					remote_branches.append(parts[1])
		return list(set(remote_branches))
	except (GitError, Pygit2GitError) as e:
		PRGitUtils.logger.debug(f"Error getting remote branches: {e}")
		return []
	except Exception as e:  # noqa: BLE001
		PRGitUtils.logger.debug(f"Unexpected error getting remote branches: {e}")
		return []

get_local_branches

get_local_branches() -> list[str]

Get list of local branches.

Returns:

Type Description
list[str]

List of local branch names

Source code in src/codemap/git/pr_generator/strategies.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def get_local_branches(self) -> list[str]:
	"""
	Get list of local branches.

	Returns:
	    List of local branch names

	"""
	try:
		pgu = PRGitUtils.get_instance()
		return list(pgu.repo.branches.local)
	except (GitError, Pygit2GitError) as e:
		PRGitUtils.logger.debug(f"Error getting local branches: {e}")
		return []
	except Exception as e:  # noqa: BLE001
		PRGitUtils.logger.debug(f"Unexpected error getting local branches: {e}")
		return []

get_branches_by_type

get_branches_by_type() -> dict[str, list[str]]

Group branches by their type.

Returns:

Type Description
dict[str, list[str]]

Dictionary mapping branch types to lists of branch names

Source code in src/codemap/git/pr_generator/strategies.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def get_branches_by_type(self) -> dict[str, list[str]]:
	"""
	Group branches by their type.

	Returns:
	    Dictionary mapping branch types to lists of branch names

	"""
	result = {branch_type: [] for branch_type in self.get_branch_types()}
	result["other"] = []  # For branches that don't match any type

	# Get all branches (local and remote)
	all_branches = set(self.get_local_branches() + self.get_remote_branches())

	for branch in all_branches:
		branch_type = self.detect_branch_type(branch)
		if branch_type:
			result[branch_type].append(branch)
		else:
			result["other"].append(branch)

	return result

get_branch_metadata

get_branch_metadata(branch_name: str) -> dict[str, Any]

Get metadata for a specific branch.

Parameters:

Name Type Description Default
branch_name str

Name of the branch

required

Returns:

Type Description
dict[str, Any]

Dictionary with branch metadata

Source code in src/codemap/git/pr_generator/strategies.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def get_branch_metadata(self, branch_name: str) -> dict[str, Any]:
	"""
	Get metadata for a specific branch.

	Args:
	    branch_name: Name of the branch

	Returns:
	    Dictionary with branch metadata

	"""
	try:
		pgu = PRGitUtils.get_instance()
		repo = pgu.repo

		# Determine full ref for revparse_single (try local, then remote)
		branch_ref_to_parse = branch_name
		if not branch_exists(branch_name, pgu_instance=pgu, include_remote=False) and branch_exists(
			branch_name, pgu_instance=pgu, remote_name="origin", include_local=False
		):
			branch_ref_to_parse = f"origin/{branch_name}"
		# If still not found by branch_exists, revparse_single might fail, which is caught below.

		last_commit_iso_date = "unknown"
		try:
			commit_obj = repo.revparse_single(branch_ref_to_parse).peel(Commit)
			commit_time = datetime.fromtimestamp(commit_obj.commit_time, tz=UTC)
			last_commit_iso_date = commit_time.isoformat()
		except (Pygit2GitError, GitError) as e:  # Catch errors resolving commit
			PRGitUtils.logger.debug(f"Could not get last commit date for {branch_ref_to_parse}: {e}")

		commit_count_str = "0"
		try:
			default_b = get_default_branch(pgu_instance=pgu)
			if default_b:
				# get_branch_relation expects full ref names or resolvable names
				_, count = pgu.get_branch_relation(default_b, branch_ref_to_parse)
				commit_count_str = str(count)
		except (GitError, Pygit2GitError) as e:
			PRGitUtils.logger.debug(f"Could not get commit count for {branch_ref_to_parse} vs default: {e}")

		branch_type_detected = self.detect_branch_type(branch_name)

		return {
			"last_commit_date": last_commit_iso_date,
			"commit_count": commit_count_str,
			"branch_type": branch_type_detected,
			"is_local": branch_exists(branch_name, pgu_instance=pgu, include_remote=False, include_local=True),
			"is_remote": branch_exists(branch_name, pgu_instance=pgu, remote_name="origin", include_local=False),
		}
	except (GitError, Pygit2GitError) as e:
		PRGitUtils.logger.warning(f"Error getting branch metadata for {branch_name}: {e}")
		return {  # Fallback for broader errors during pgu instantiation or initial checks
			"last_commit_date": "unknown",
			"commit_count": "0",
			"branch_type": self.detect_branch_type(branch_name),
			"is_local": False,
			"is_remote": False,
		}
	except Exception as e:  # noqa: BLE001
		PRGitUtils.logger.warning(f"Unexpected error getting branch metadata for {branch_name}: {e}")
		return {
			"last_commit_date": "unknown",
			"commit_count": "0",
			"branch_type": self.detect_branch_type(branch_name),
			"is_local": False,
			"is_remote": False,
		}

get_all_branches_with_metadata

get_all_branches_with_metadata() -> dict[
	str, dict[str, Any]
]

Get all branches with metadata.

Returns:

Type Description
dict[str, dict[str, Any]]

Dictionary mapping branch names to metadata dictionaries

Source code in src/codemap/git/pr_generator/strategies.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_all_branches_with_metadata(self) -> dict[str, dict[str, Any]]:
	"""
	Get all branches with metadata.

	Returns:
	    Dictionary mapping branch names to metadata dictionaries

	"""
	result = {}
	# Using PRGitUtils for a consistent list of branches
	pgu = PRGitUtils.get_instance()
	local_b = list(pgu.repo.branches.local)
	remote_b_parsed = []
	for rb_name in pgu.repo.branches.remote:
		if rb_name.startswith("origin/") and not rb_name.endswith("/HEAD"):
			remote_b_parsed.append(rb_name[len("origin/") :])
		elif "/" in rb_name and not rb_name.endswith("/HEAD"):
			parts = rb_name.split("/", 1)
			if len(parts) > 1:
				remote_b_parsed.append(parts[1])

	all_branches = set(local_b + remote_b_parsed)

	for branch in all_branches:
		result[branch] = self.get_branch_metadata(branch)

	return result

GitHubFlowStrategy

Bases: WorkflowStrategy

Implementation of GitHub Flow workflow strategy.

Source code in src/codemap/git/pr_generator/strategies.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
class GitHubFlowStrategy(WorkflowStrategy):
	"""Implementation of GitHub Flow workflow strategy."""

	def get_default_base(self, branch_type: str) -> str | None:  # noqa: ARG002
		"""
		Get the default base branch for GitHub Flow.

		Args:
		    branch_type: Type of branch (always 'feature' in GitHub Flow)

		Returns:
		    Name of the default base branch (usually 'main')

		"""
		# Ignoring branch_type as GitHub Flow always uses the default branch
		return get_default_branch()

	def get_branch_prefix(self, branch_type: str) -> str:  # noqa: ARG002
		"""
		Get the branch name prefix for GitHub Flow.

		Args:
		    branch_type: Type of branch (always 'feature' in GitHub Flow)

		Returns:
		    Branch name prefix (empty string for GitHub Flow)

		"""
		# Ignoring branch_type as GitHub Flow doesn't use prefixes
		return ""

	def get_branch_types(self) -> list[str]:
		"""
		Get valid branch types for GitHub Flow.

		Returns:
		    List containing only 'feature'

		"""
		return ["feature"]

	def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
		"""
		Get PR title and description templates for GitHub Flow.

		Args:
		    branch_type: Type of branch (always 'feature' in GitHub Flow)

		Returns:
		    Dictionary with 'title' and 'description' templates

		"""
		return GITHUB_FLOW_PR_TEMPLATE

get_default_base

get_default_base(branch_type: str) -> str | None

Get the default base branch for GitHub Flow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (always 'feature' in GitHub Flow)

required

Returns:

Type Description
str | None

Name of the default base branch (usually 'main')

Source code in src/codemap/git/pr_generator/strategies.py
283
284
285
286
287
288
289
290
291
292
293
294
295
def get_default_base(self, branch_type: str) -> str | None:  # noqa: ARG002
	"""
	Get the default base branch for GitHub Flow.

	Args:
	    branch_type: Type of branch (always 'feature' in GitHub Flow)

	Returns:
	    Name of the default base branch (usually 'main')

	"""
	# Ignoring branch_type as GitHub Flow always uses the default branch
	return get_default_branch()

get_branch_prefix

get_branch_prefix(branch_type: str) -> str

Get the branch name prefix for GitHub Flow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (always 'feature' in GitHub Flow)

required

Returns:

Type Description
str

Branch name prefix (empty string for GitHub Flow)

Source code in src/codemap/git/pr_generator/strategies.py
297
298
299
300
301
302
303
304
305
306
307
308
309
def get_branch_prefix(self, branch_type: str) -> str:  # noqa: ARG002
	"""
	Get the branch name prefix for GitHub Flow.

	Args:
	    branch_type: Type of branch (always 'feature' in GitHub Flow)

	Returns:
	    Branch name prefix (empty string for GitHub Flow)

	"""
	# Ignoring branch_type as GitHub Flow doesn't use prefixes
	return ""

get_branch_types

get_branch_types() -> list[str]

Get valid branch types for GitHub Flow.

Returns:

Type Description
list[str]

List containing only 'feature'

Source code in src/codemap/git/pr_generator/strategies.py
311
312
313
314
315
316
317
318
319
def get_branch_types(self) -> list[str]:
	"""
	Get valid branch types for GitHub Flow.

	Returns:
	    List containing only 'feature'

	"""
	return ["feature"]

get_pr_templates

get_pr_templates(branch_type: str) -> dict[str, str]

Get PR title and description templates for GitHub Flow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (always 'feature' in GitHub Flow)

required

Returns:

Type Description
dict[str, str]

Dictionary with 'title' and 'description' templates

Source code in src/codemap/git/pr_generator/strategies.py
321
322
323
324
325
326
327
328
329
330
331
332
def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
	"""
	Get PR title and description templates for GitHub Flow.

	Args:
	    branch_type: Type of branch (always 'feature' in GitHub Flow)

	Returns:
	    Dictionary with 'title' and 'description' templates

	"""
	return GITHUB_FLOW_PR_TEMPLATE

GitFlowStrategy

Bases: WorkflowStrategy

Implementation of GitFlow workflow strategy.

Source code in src/codemap/git/pr_generator/strategies.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
class GitFlowStrategy(WorkflowStrategy):
	"""Implementation of GitFlow workflow strategy."""

	def get_default_base(self, branch_type: str) -> str | None:
		"""
		Get the default base branch for GitFlow.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, bugfix)

		Returns:
		    Name of the default base branch

		"""
		mapping = {
			"feature": "develop",
			"release": "main",
			"hotfix": "main",
			"bugfix": "develop",
		}
		default = get_default_branch()
		return mapping.get(branch_type, default)

	def get_branch_prefix(self, branch_type: str) -> str:
		"""
		Get the branch name prefix for GitFlow.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)

		Returns:
		    Branch name prefix

		"""
		mapping = {
			"feature": "feature/",
			"release": "release/",
			"hotfix": "hotfix/",
			"bugfix": "bugfix/",
		}
		return mapping.get(branch_type, "")

	def get_branch_types(self) -> list[str]:
		"""
		Get valid branch types for GitFlow.

		Returns:
		    List of valid branch types for GitFlow

		"""
		return ["feature", "release", "hotfix", "bugfix"]

	def suggest_branch_name(self, branch_type: str, description: str) -> str:
		"""
		Suggest a branch name based on GitFlow conventions.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, etc.)
		    description: Description of the branch

		Returns:
		    Suggested branch name

		"""
		prefix = self.get_branch_prefix(branch_type)

		if branch_type == "release":
			# Extract version number from description if it looks like a version
			version_match = re.search(r"(\d+\.\d+\.\d+)", description)
			if version_match:
				return f"{prefix}{version_match.group(1)}"

		# For other branch types, use the default implementation
		return super().suggest_branch_name(branch_type, description)

	def get_pr_templates(self, branch_type: str) -> dict[str, str]:
		"""
		Get PR title and description templates for GitFlow.

		Args:
		    branch_type: Type of branch (feature, release, hotfix, bugfix)

		Returns:
		    Dictionary with 'title' and 'description' templates

		"""
		return GITFLOW_PR_TEMPLATES.get(branch_type, DEFAULT_PR_TEMPLATE)

get_default_base

get_default_base(branch_type: str) -> str | None

Get the default base branch for GitFlow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, bugfix)

required

Returns:

Type Description
str | None

Name of the default base branch

Source code in src/codemap/git/pr_generator/strategies.py
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
def get_default_base(self, branch_type: str) -> str | None:
	"""
	Get the default base branch for GitFlow.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, bugfix)

	Returns:
	    Name of the default base branch

	"""
	mapping = {
		"feature": "develop",
		"release": "main",
		"hotfix": "main",
		"bugfix": "develop",
	}
	default = get_default_branch()
	return mapping.get(branch_type, default)

get_branch_prefix

get_branch_prefix(branch_type: str) -> str

Get the branch name prefix for GitFlow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required

Returns:

Type Description
str

Branch name prefix

Source code in src/codemap/git/pr_generator/strategies.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
def get_branch_prefix(self, branch_type: str) -> str:
	"""
	Get the branch name prefix for GitFlow.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)

	Returns:
	    Branch name prefix

	"""
	mapping = {
		"feature": "feature/",
		"release": "release/",
		"hotfix": "hotfix/",
		"bugfix": "bugfix/",
	}
	return mapping.get(branch_type, "")

get_branch_types

get_branch_types() -> list[str]

Get valid branch types for GitFlow.

Returns:

Type Description
list[str]

List of valid branch types for GitFlow

Source code in src/codemap/git/pr_generator/strategies.py
377
378
379
380
381
382
383
384
385
def get_branch_types(self) -> list[str]:
	"""
	Get valid branch types for GitFlow.

	Returns:
	    List of valid branch types for GitFlow

	"""
	return ["feature", "release", "hotfix", "bugfix"]

suggest_branch_name

suggest_branch_name(
	branch_type: str, description: str
) -> str

Suggest a branch name based on GitFlow conventions.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, etc.)

required
description str

Description of the branch

required

Returns:

Type Description
str

Suggested branch name

Source code in src/codemap/git/pr_generator/strategies.py
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
def suggest_branch_name(self, branch_type: str, description: str) -> str:
	"""
	Suggest a branch name based on GitFlow conventions.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, etc.)
	    description: Description of the branch

	Returns:
	    Suggested branch name

	"""
	prefix = self.get_branch_prefix(branch_type)

	if branch_type == "release":
		# Extract version number from description if it looks like a version
		version_match = re.search(r"(\d+\.\d+\.\d+)", description)
		if version_match:
			return f"{prefix}{version_match.group(1)}"

	# For other branch types, use the default implementation
	return super().suggest_branch_name(branch_type, description)

get_pr_templates

get_pr_templates(branch_type: str) -> dict[str, str]

Get PR title and description templates for GitFlow.

Parameters:

Name Type Description Default
branch_type str

Type of branch (feature, release, hotfix, bugfix)

required

Returns:

Type Description
dict[str, str]

Dictionary with 'title' and 'description' templates

Source code in src/codemap/git/pr_generator/strategies.py
410
411
412
413
414
415
416
417
418
419
420
421
def get_pr_templates(self, branch_type: str) -> dict[str, str]:
	"""
	Get PR title and description templates for GitFlow.

	Args:
	    branch_type: Type of branch (feature, release, hotfix, bugfix)

	Returns:
	    Dictionary with 'title' and 'description' templates

	"""
	return GITFLOW_PR_TEMPLATES.get(branch_type, DEFAULT_PR_TEMPLATE)

TrunkBasedStrategy

Bases: WorkflowStrategy

Implementation of Trunk-Based Development workflow strategy.

Source code in src/codemap/git/pr_generator/strategies.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
class TrunkBasedStrategy(WorkflowStrategy):
	"""Implementation of Trunk-Based Development workflow strategy."""

	def get_default_base(self, branch_type: str) -> str | None:  # noqa: ARG002
		"""
		Get the default base branch for Trunk-Based Development.

		Args:
		    branch_type: Type of branch

		Returns:
		    Name of the default base branch (trunk, which is usually 'main')

		"""
		# Ignoring branch_type as Trunk-Based Development always uses the main branch
		return get_default_branch()

	def get_branch_prefix(self, branch_type: str) -> str:
		"""
		Get the branch name prefix for Trunk-Based Development.

		Args:
		    branch_type: Type of branch

		Returns:
		    Branch name prefix

		"""
		return "fb/" if branch_type == "feature" else ""

	def get_branch_types(self) -> list[str]:
		"""
		Get valid branch types for Trunk-Based Development.

		Returns:
		    List containing only 'feature'

		"""
		return ["feature"]

	def suggest_branch_name(self, branch_type: str, description: str) -> str:
		"""
		Suggest a branch name based on Trunk-Based Development conventions.

		Emphasizes short-lived, descriptive branches.

		Args:
		    branch_type: Type of branch
		    description: Description of the branch

		Returns:
		    Suggested branch name

		"""
		# For trunk-based development, try to generate very short names
		words = description.split()
		# Filter out common words like "implement", "the", "and", etc.
		common_words = ["the", "and", "for", "with", "implement", "implementing", "implementation"]
		words = [w for w in words if len(w) > MIN_SIGNIFICANT_WORD_LENGTH and w.lower() not in common_words]

		# Take up to 3 significant words
		short_desc = "-".join(words[:3]).lower()
		short_desc = re.sub(r"[^a-zA-Z0-9-]", "-", short_desc)
		short_desc = re.sub(r"-+", "-", short_desc)
		short_desc = short_desc.strip("-")

		# Add username prefix for trunk-based (optional)
		try:
			pgu = PRGitUtils.get_instance()
			# Ensure config is available and handle potential errors
			user_name_config = pgu.repo.config["user.name"]
			if user_name_config:
				# Ensure user_name_config is treated as a string before strip/split
				username = str(user_name_config).strip().split()[0].lower()
				username = re.sub(r"[^a-zA-Z0-9]", "", username)
				return f"{username}/{short_desc if short_desc else 'update'}"  # ensure short_desc is not empty
			# Fallback if username is not configured
			prefix = self.get_branch_prefix(branch_type)
			return f"{prefix}{short_desc if short_desc else 'update'}"
		except (GitError, Pygit2GitError, KeyError, IndexError, AttributeError) as e:  # Catch more specific errors
			PRGitUtils.logger.debug(f"Could not get username for branch prefix: {e}")
			prefix = self.get_branch_prefix(branch_type)
			return f"{prefix}{short_desc if short_desc else 'update'}"
		except Exception as e:  # noqa: BLE001
			PRGitUtils.logger.debug(f"Unexpected error getting username for branch prefix: {e}")
			prefix = self.get_branch_prefix(branch_type)
			return f"{prefix}{short_desc if short_desc else 'update'}"

	def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
		"""
		Get PR title and description templates for Trunk-Based Development.

		Args:
		    branch_type: Type of branch

		Returns:
		    Dictionary with 'title' and 'description' templates

		"""
		return TRUNK_BASED_PR_TEMPLATE

get_default_base

get_default_base(branch_type: str) -> str | None

Get the default base branch for Trunk-Based Development.

Parameters:

Name Type Description Default
branch_type str

Type of branch

required

Returns:

Type Description
str | None

Name of the default base branch (trunk, which is usually 'main')

Source code in src/codemap/git/pr_generator/strategies.py
427
428
429
430
431
432
433
434
435
436
437
438
439
def get_default_base(self, branch_type: str) -> str | None:  # noqa: ARG002
	"""
	Get the default base branch for Trunk-Based Development.

	Args:
	    branch_type: Type of branch

	Returns:
	    Name of the default base branch (trunk, which is usually 'main')

	"""
	# Ignoring branch_type as Trunk-Based Development always uses the main branch
	return get_default_branch()

get_branch_prefix

get_branch_prefix(branch_type: str) -> str

Get the branch name prefix for Trunk-Based Development.

Parameters:

Name Type Description Default
branch_type str

Type of branch

required

Returns:

Type Description
str

Branch name prefix

Source code in src/codemap/git/pr_generator/strategies.py
441
442
443
444
445
446
447
448
449
450
451
452
def get_branch_prefix(self, branch_type: str) -> str:
	"""
	Get the branch name prefix for Trunk-Based Development.

	Args:
	    branch_type: Type of branch

	Returns:
	    Branch name prefix

	"""
	return "fb/" if branch_type == "feature" else ""

get_branch_types

get_branch_types() -> list[str]

Get valid branch types for Trunk-Based Development.

Returns:

Type Description
list[str]

List containing only 'feature'

Source code in src/codemap/git/pr_generator/strategies.py
454
455
456
457
458
459
460
461
462
def get_branch_types(self) -> list[str]:
	"""
	Get valid branch types for Trunk-Based Development.

	Returns:
	    List containing only 'feature'

	"""
	return ["feature"]

suggest_branch_name

suggest_branch_name(
	branch_type: str, description: str
) -> str

Suggest a branch name based on Trunk-Based Development conventions.

Emphasizes short-lived, descriptive branches.

Parameters:

Name Type Description Default
branch_type str

Type of branch

required
description str

Description of the branch

required

Returns:

Type Description
str

Suggested branch name

Source code in src/codemap/git/pr_generator/strategies.py
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
def suggest_branch_name(self, branch_type: str, description: str) -> str:
	"""
	Suggest a branch name based on Trunk-Based Development conventions.

	Emphasizes short-lived, descriptive branches.

	Args:
	    branch_type: Type of branch
	    description: Description of the branch

	Returns:
	    Suggested branch name

	"""
	# For trunk-based development, try to generate very short names
	words = description.split()
	# Filter out common words like "implement", "the", "and", etc.
	common_words = ["the", "and", "for", "with", "implement", "implementing", "implementation"]
	words = [w for w in words if len(w) > MIN_SIGNIFICANT_WORD_LENGTH and w.lower() not in common_words]

	# Take up to 3 significant words
	short_desc = "-".join(words[:3]).lower()
	short_desc = re.sub(r"[^a-zA-Z0-9-]", "-", short_desc)
	short_desc = re.sub(r"-+", "-", short_desc)
	short_desc = short_desc.strip("-")

	# Add username prefix for trunk-based (optional)
	try:
		pgu = PRGitUtils.get_instance()
		# Ensure config is available and handle potential errors
		user_name_config = pgu.repo.config["user.name"]
		if user_name_config:
			# Ensure user_name_config is treated as a string before strip/split
			username = str(user_name_config).strip().split()[0].lower()
			username = re.sub(r"[^a-zA-Z0-9]", "", username)
			return f"{username}/{short_desc if short_desc else 'update'}"  # ensure short_desc is not empty
		# Fallback if username is not configured
		prefix = self.get_branch_prefix(branch_type)
		return f"{prefix}{short_desc if short_desc else 'update'}"
	except (GitError, Pygit2GitError, KeyError, IndexError, AttributeError) as e:  # Catch more specific errors
		PRGitUtils.logger.debug(f"Could not get username for branch prefix: {e}")
		prefix = self.get_branch_prefix(branch_type)
		return f"{prefix}{short_desc if short_desc else 'update'}"
	except Exception as e:  # noqa: BLE001
		PRGitUtils.logger.debug(f"Unexpected error getting username for branch prefix: {e}")
		prefix = self.get_branch_prefix(branch_type)
		return f"{prefix}{short_desc if short_desc else 'update'}"

get_pr_templates

get_pr_templates(branch_type: str) -> dict[str, str]

Get PR title and description templates for Trunk-Based Development.

Parameters:

Name Type Description Default
branch_type str

Type of branch

required

Returns:

Type Description
dict[str, str]

Dictionary with 'title' and 'description' templates

Source code in src/codemap/git/pr_generator/strategies.py
512
513
514
515
516
517
518
519
520
521
522
523
def get_pr_templates(self, branch_type: str) -> dict[str, str]:  # noqa: ARG002
	"""
	Get PR title and description templates for Trunk-Based Development.

	Args:
	    branch_type: Type of branch

	Returns:
	    Dictionary with 'title' and 'description' templates

	"""
	return TRUNK_BASED_PR_TEMPLATE

get_strategy_class

get_strategy_class(
	strategy_name: str,
) -> type[WorkflowStrategy] | None

Get the workflow strategy class corresponding to the strategy name.

Parameters:

Name Type Description Default
strategy_name str

Name of the workflow strategy

required

Returns:

Type Description
type[WorkflowStrategy] | None

Workflow strategy class or None if not found

Source code in src/codemap/git/pr_generator/strategies.py
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
def get_strategy_class(strategy_name: str) -> type[WorkflowStrategy] | None:
	"""
	Get the workflow strategy class corresponding to the strategy name.

	Args:
	    strategy_name: Name of the workflow strategy

	Returns:
	    Workflow strategy class or None if not found

	"""
	strategy_map = {
		"github-flow": GitHubFlowStrategy,
		"gitflow": GitFlowStrategy,
		"trunk-based": TrunkBasedStrategy,
	}
	return strategy_map.get(strategy_name)

create_strategy

create_strategy(strategy_name: str) -> WorkflowStrategy

Create a workflow strategy instance based on the strategy name.

Parameters:

Name Type Description Default
strategy_name str

The name of the workflow strategy to create.

required

Returns:

Type Description
WorkflowStrategy

An instance of the requested workflow strategy.

Raises:

Type Description
ValueError

If the strategy name is unknown.

Source code in src/codemap/git/pr_generator/strategies.py
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
def create_strategy(strategy_name: str) -> WorkflowStrategy:
	"""
	Create a workflow strategy instance based on the strategy name.

	Args:
	    strategy_name: The name of the workflow strategy to create.

	Returns:
	    An instance of the requested workflow strategy.

	Raises:
	    ValueError: If the strategy name is unknown.

	"""
	strategy_class = get_strategy_class(strategy_name)
	if not strategy_class:
		error_msg = f"Unknown workflow strategy: {strategy_name}"
		raise ValueError(error_msg)

	return strategy_class()

branch_exists

branch_exists(
	branch_name: str,
	pgu_instance: PRGitUtils | None = None,
	remote_name: str = "origin",
	include_remote: bool = True,
	include_local: bool = True,
) -> bool

Check if a branch exists using pygit2.

Parameters:

Name Type Description Default
branch_name str

Name of the branch to check (e.g., "main", "feature/foo").

required
pgu_instance PRGitUtils | None

Optional instance of PRGitUtils. If None, one will be created.

None
remote_name str

The name of the remote to check (default: "origin").

'origin'
include_remote bool

Whether to check remote branches.

True
include_local bool

Whether to check local branches.

True

Returns:

Type Description
bool

True if the branch exists in the specified locations, False otherwise.

Source code in src/codemap/git/pr_generator/strategies.py
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
def branch_exists(
	branch_name: str,
	pgu_instance: PRGitUtils | None = None,
	remote_name: str = "origin",
	include_remote: bool = True,
	include_local: bool = True,
) -> bool:
	"""
	Check if a branch exists using pygit2.

	Args:
	    branch_name: Name of the branch to check (e.g., "main", "feature/foo").
	    pgu_instance: Optional instance of PRGitUtils. If None, one will be created.
	    remote_name: The name of the remote to check (default: "origin").
	    include_remote: Whether to check remote branches.
	    include_local: Whether to check local branches.

	Returns:
	    True if the branch exists in the specified locations, False otherwise.
	"""
	if not branch_name:
		return False

	pgu = pgu_instance or PRGitUtils.get_instance()
	repo = pgu.repo

	if include_local:
		try:
			# lookup_branch checks local branches by default if branch_type is not specified
			# or if BranchType.LOCAL is used.
			if repo.lookup_branch(branch_name, BranchType.LOCAL):  # Explicitly check local
				return True
		except (KeyError, Pygit2GitError):  # lookup_branch raises KeyError if not found
			pass  # Not found locally

	if include_remote:
		remote_branch_ref = f"{remote_name}/{branch_name}"
		try:
			# To check a remote branch, we look it up by its full remote-prefixed name
			# in the list of remote branches pygit2 knows.
			# An alternative is repo.lookup_reference(f"refs/remotes/{remote_name}/{branch_name}")
			if remote_branch_ref in repo.branches.remote:
				return True
		except (KeyError, Pygit2GitError):  # Should not happen with `in` check
			pass  # Not found remotely

	return False

get_default_branch

get_default_branch(
	pgu_instance: PRGitUtils | None = None,
) -> str

Get the default branch of the repository using pygit2.

Parameters:

Name Type Description Default
pgu_instance PRGitUtils | None

Optional instance of PRGitUtils.

None

Returns:

Type Description
str

Name of the default branch (e.g., "main", "master").

Source code in src/codemap/git/pr_generator/strategies.py
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
def get_default_branch(pgu_instance: PRGitUtils | None = None) -> str:
	"""
	Get the default branch of the repository using pygit2.

	Args:
	    pgu_instance: Optional instance of PRGitUtils.

	Returns:
	    Name of the default branch (e.g., "main", "master").
	"""
	pgu = pgu_instance or PRGitUtils.get_instance()
	repo = pgu.repo
	try:
		if not repo.head_is_detached:
			# Current HEAD is a symbolic ref to a branch, this is often the default
			# if on the default branch.
			# However, this returns the current branch, not necessarily default.
			# current_branch = repo.head.shorthand
			# if current_branch in ["main", "master"]: return current_branch
			pass  # Fall through to more robust checks for default

		# Try to get the symbolic-ref of refs/remotes/origin/HEAD
		try:
			origin_head_ref = repo.lookup_reference("refs/remotes/origin/HEAD")
			if origin_head_ref and origin_head_ref.type == ReferenceType.SYMBOLIC:
				target_as_val = origin_head_ref.target
				# Target is like 'refs/remotes/origin/main'
				# If type is SYMBOLIC, target should be str. Add isinstance to help linter.
				if isinstance(target_as_val, str) and target_as_val.startswith("refs/remotes/origin/"):
					return target_as_val[len("refs/remotes/origin/") :]
		except (KeyError, Pygit2GitError):
			pass  # origin/HEAD might not exist or not be symbolic

		# Fallback: check for common default branch names ('main', then 'master')
		# Check remote branches first as they are more indicative of shared default
		if "origin/main" in repo.branches.remote:
			return "main"
		if "origin/master" in repo.branches.remote:
			return "master"
		# Then check local branches
		if "main" in repo.branches.local:
			return "main"
		if "master" in repo.branches.local:
			return "master"

		# If still not found, and HEAD is not detached, use current branch as last resort.
		if not repo.head_is_detached:
			return repo.head.shorthand

	except (GitError, Pygit2GitError) as e:
		PRGitUtils.logger.warning(f"Could not determine default branch via pygit2: {e}. Falling back to 'main'.")
	except Exception as e:  # noqa: BLE001
		PRGitUtils.logger.warning(f"Unexpected error determining default branch: {e}. Falling back to 'main'.")

	return "main"  # Ultimate fallback