@intentsolutionsio/devops-automation-pack 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,114 @@
1
+ # Commit Message Template
2
+
3
+ This template provides a standardized format for creating clear and informative commit messages. Using this template will improve team communication, code review, and project maintainability.
4
+
5
+ ## Format
6
+
7
+ ```
8
+ <type>(<scope>): <subject>
9
+
10
+ [optional body]
11
+
12
+ [optional footer(s)]
13
+ ```
14
+
15
+ ## Sections
16
+
17
+ ### Type
18
+
19
+ The type of commit. Choose from the following:
20
+
21
+ * **feat:** A new feature
22
+ * **fix:** A bug fix
23
+ * **docs:** Documentation only changes
24
+ * **style:** Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
25
+ * **refactor:** A code change that neither fixes a bug nor adds a feature
26
+ * **perf:** A code change that improves performance
27
+ * **test:** Adding missing tests or correcting existing tests
28
+ * **build:** Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
29
+ * **ci:** Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
30
+ * **chore:** Other changes that don't modify src or test files
31
+ * **revert:** Reverts a previous commit
32
+
33
+ **Example:** `feat(user-authentication): Implement password reset functionality`
34
+
35
+ ### Scope
36
+
37
+ The scope of the commit. This could be a module, component, or area of the codebase affected by the change. Keep it concise.
38
+
39
+ **Example:** `feat(api): Add endpoint for retrieving user profiles`
40
+
41
+ ### Subject
42
+
43
+ A brief and concise description of the change. Use the imperative, present tense: "change" not "changed" nor "changes".
44
+
45
+ * Limit to 50 characters.
46
+ * Do not end with a period.
47
+
48
+ **Example:** `fix(layout): Correct alignment issues on mobile devices`
49
+
50
+ ### Body (Optional)
51
+
52
+ A more detailed explanation of the change. Use the imperative, present tense. Explain the *why* and *how*.
53
+
54
+ * Wrap lines at 72 characters.
55
+ * Can include multiple paragraphs.
56
+ * Use bullet points for lists when appropriate.
57
+
58
+ **Example:**
59
+
60
+ ```
61
+ This commit addresses a critical bug in the user authentication module. The previous implementation allowed users to bypass the password reset process under certain circumstances.
62
+
63
+ This was achieved by:
64
+
65
+ * Adding a validation check to ensure the password reset token is valid.
66
+ * Implementing rate limiting to prevent brute-force attacks.
67
+ * Improving error handling to provide more informative feedback to the user.
68
+ ```
69
+
70
+ ### Footer (Optional)
71
+
72
+ * **Breaking Changes:** If the commit introduces a breaking change, describe the change, justification, and migration notes. Start with `BREAKING CHANGE:`.
73
+ * **Related Issues:** Refer to related issues using `Closes #<issue_number>`, `Fixes #<issue_number>`, or `See #<issue_number>`.
74
+ * **Co-authored-by:** Credit collaborators using `Co-authored-by: Name <email@example.com>`.
75
+
76
+ **Example - Breaking Change:**
77
+
78
+ ```
79
+ BREAKING CHANGE: The API endpoint for retrieving user profiles has been renamed from `/users` to `/profiles`.
80
+
81
+ Migration: Update all client applications to use the new endpoint.
82
+ ```
83
+
84
+ **Example - Issue Fix:**
85
+
86
+ ```
87
+ Fixes #123: Resolved issue where users were unable to log in.
88
+ ```
89
+
90
+ ## Example Commit Message
91
+
92
+ ```
93
+ feat(payment-gateway): Integrate Stripe payment processing
94
+
95
+ This commit adds support for Stripe payment processing to the application.
96
+
97
+ The following changes were made:
98
+
99
+ * Implemented the Stripe API integration.
100
+ * Added a new payment form to the checkout page.
101
+ * Updated the database schema to store payment information.
102
+
103
+ Closes #456: Implement Stripe integration
104
+ ```
105
+
106
+ ## Best Practices
107
+
108
+ * Write clear and concise commit messages.
109
+ * Use the imperative, present tense.
110
+ * Limit the subject line to 50 characters.
111
+ * Provide context in the body of the message.
112
+ * Include relevant information in the footer.
113
+ * Review your commit messages before pushing them.
114
+ * Be consistent with your commit message style.
@@ -0,0 +1,64 @@
1
+ # Example Code Diff for Commit Message Generation
2
+
3
+ This document provides an example code diff that can be used by the `devops-automation-pack` plugin to generate commit messages. The `example_code_diff.txt` file should contain the raw diff output. This file is used as input for plugins like `generate_commit_message` within the `devops-automation-pack`.
4
+
5
+ ## Purpose
6
+
7
+ The purpose of this file is to provide a clear and concise example of a code diff, which the `generate_commit_message` plugin uses to create informative and helpful commit messages. This helps developers write better commit messages, improving code maintainability and collaboration.
8
+
9
+ ## File Contents (example_code_diff.txt)
10
+
11
+ ```
12
+ --- a/example.py
13
+ +++ b/example.py
14
+ @@ -1,4 +1,5 @@
15
+ def hello_world():
16
+ - print("Hello, world!")
17
+ + message = "Hello, world!"
18
+ + print(message)
19
+
20
+ hello_world()
21
+
22
+ ```
23
+
24
+ ## Explanation
25
+
26
+ The above diff shows a simple change to the `example.py` file. Specifically, it shows:
27
+
28
+ * **`--- a/example.py`**: Indicates the original file (`example.py`) before the changes.
29
+ * **`+++ b/example.py`**: Indicates the modified file (`example.py`) after the changes.
30
+ * **`@@ -1,4 +1,5 @@`**: Indicates the line numbers that were changed. `-1,4` means lines 1 through 4 in the original file. `+1,5` means lines 1 through 5 in the modified file.
31
+ * **`- print("Hello, world!")`**: The line that was removed (indicated by the `-`).
32
+ * **`+ message = "Hello, world!"`**: The first line added (indicated by the `+`).
33
+ * **`+ print(message)`**: The second line added (indicated by the `+`).
34
+
35
+ ## How to Use This File
36
+
37
+ 1. **Replace the contents:** Replace the contents of the `example_code_diff.txt` file with a real code diff that you want to use to generate a commit message. You can obtain this diff using `git diff` or a similar tool.
38
+ 2. **Integrate with the plugin:** Refer to the `devops-automation-pack` plugin documentation for instructions on how to use this file as input for the `generate_commit_message` plugin (or similar plugins that utilize diffs). The plugin will typically read the content of this file and use it to intelligently generate a suggested commit message.
39
+
40
+ ## Example Plugin Usage (Conceptual)
41
+
42
+ ```
43
+ # Example Python code demonstrating how the plugin might use the diff file
44
+ # (This is an illustrative example and might not be the exact API)
45
+
46
+ from devops_automation_pack import generate_commit_message
47
+
48
+ with open("example_code_diff.txt", "r") as f:
49
+ code_diff = f.read()
50
+
51
+ commit_message = generate_commit_message(code_diff)
52
+ print(commit_message)
53
+ ```
54
+
55
+ ## Best Practices
56
+
57
+ * **Ensure the diff is clean:** Make sure the diff is free of merge conflicts or other extraneous information. A clean diff will result in a better commit message.
58
+ * **Review the generated message:** Always review the generated commit message before committing the changes. The AI-generated message is a suggestion, and you should always ensure it accurately reflects the changes made.
59
+ * **Use descriptive diffs:** The more descriptive the diff, the better the AI will be able to understand the changes and generate a relevant commit message.
60
+
61
+ ## Troubleshooting
62
+
63
+ * **Plugin not generating a message:** Double-check that the `example_code_diff.txt` file exists and contains valid diff output.
64
+ * **Poor quality message:** Try simplifying the diff or providing additional context to the plugin (if the plugin supports it). Also, remember to always review and edit the generated message.
@@ -0,0 +1,4 @@
1
+ # References
2
+
3
+ Bundled resources for devops-automation-pack skill
4
+
@@ -0,0 +1,7 @@
1
+ # Scripts
2
+
3
+ Bundled resources for devops-automation-pack skill
4
+
5
+ - [x] validate_commit_message.py: Validates a commit message against the conventional commits specification.
6
+ - [x] generate_commit_message.py: Generates a commit message based on code diffs.
7
+ - [x] suggest_commit_type.py: Suggests the commit type (feat, fix, chore, etc.) based on the changes.
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate conventional commit messages based on code diffs.
4
+
5
+ This script analyzes git diffs and generates appropriate commit messages
6
+ following the conventional commits specification. It examines the types
7
+ of changes made and suggests an appropriate message format.
8
+ """
9
+
10
+ import argparse
11
+ import sys
12
+ import subprocess
13
+ import json
14
+ from pathlib import Path
15
+ from typing import Tuple, Optional
16
+
17
+
18
+ def get_git_diff(staged_only: bool = False) -> str:
19
+ """
20
+ Get the current git diff.
21
+
22
+ Args:
23
+ staged_only: If True, get only staged changes. Otherwise get unstaged.
24
+
25
+ Returns:
26
+ The git diff output as a string
27
+ """
28
+ try:
29
+ cmd = ['git', 'diff']
30
+ if staged_only:
31
+ cmd.append('--cached')
32
+
33
+ result = subprocess.run(
34
+ cmd,
35
+ capture_output=True,
36
+ text=True,
37
+ check=False
38
+ )
39
+
40
+ if result.returncode != 0:
41
+ return ""
42
+
43
+ return result.stdout
44
+ except FileNotFoundError:
45
+ return ""
46
+
47
+
48
+ def get_diff_from_file(filepath: str) -> str:
49
+ """
50
+ Read diff from a file.
51
+
52
+ Args:
53
+ filepath: Path to the diff file
54
+
55
+ Returns:
56
+ The diff content as a string
57
+ """
58
+ try:
59
+ with open(filepath, 'r', encoding='utf-8') as f:
60
+ return f.read()
61
+ except FileNotFoundError:
62
+ print(f"Error: File not found: {filepath}", file=sys.stderr)
63
+ sys.exit(1)
64
+ except IOError as e:
65
+ print(f"Error reading file: {e}", file=sys.stderr)
66
+ sys.exit(1)
67
+
68
+
69
+ def analyze_diff(diff_content: str) -> Tuple[str, str, str]:
70
+ """
71
+ Analyze diff content to suggest commit type and scope.
72
+
73
+ Args:
74
+ diff_content: The git diff content
75
+
76
+ Returns:
77
+ Tuple of (commit_type, scope, description)
78
+ """
79
+ # Initialize counters for different change types
80
+ has_tests = False
81
+ has_docs = False
82
+ has_style = False
83
+ has_feature = False
84
+ has_fix = False
85
+ files_changed = []
86
+
87
+ lines = diff_content.split('\n')
88
+
89
+ for line in lines:
90
+ # Track which files are being modified
91
+ if line.startswith('diff --git'):
92
+ # Extract filename
93
+ parts = line.split(' ')
94
+ if len(parts) >= 4:
95
+ filepath = parts[3]
96
+ files_changed.append(filepath)
97
+
98
+ # Detect test files
99
+ if 'test' in line.lower() or 'spec' in line.lower():
100
+ has_tests = True
101
+
102
+ # Detect documentation changes
103
+ if any(x in line.lower() for x in ['.md', 'readme', 'docs/', 'documentation']):
104
+ has_docs = True
105
+
106
+ # Detect style changes (formatting, whitespace)
107
+ if line.startswith('-') and line.lstrip('-').strip():
108
+ if len(line.lstrip('-').strip()) < 20: # Short lines likely style
109
+ has_style = True
110
+
111
+ # Detect feature additions (new functions, classes)
112
+ if any(x in line for x in ['def ', 'class ', 'function ', 'const ', 'let ']):
113
+ if line.startswith('+'):
114
+ has_feature = True
115
+
116
+ # Detect bug fixes (removing problematic code)
117
+ if 'bug' in line.lower() or 'fix' in line.lower():
118
+ has_fix = True
119
+
120
+ # Determine commit type
121
+ if has_fix:
122
+ commit_type = 'fix'
123
+ elif has_feature:
124
+ commit_type = 'feat'
125
+ elif has_tests:
126
+ commit_type = 'test'
127
+ elif has_docs:
128
+ commit_type = 'docs'
129
+ elif has_style:
130
+ commit_type = 'style'
131
+ else:
132
+ commit_type = 'refactor'
133
+
134
+ # Determine scope from files changed
135
+ scope = ''
136
+ if files_changed:
137
+ # Extract directory or module name from first file
138
+ first_file = files_changed[0]
139
+ parts = Path(first_file).parts
140
+ if len(parts) > 1:
141
+ scope = parts[0]
142
+
143
+ # Create description
144
+ description = f"Update code based on diff analysis"
145
+
146
+ return commit_type, scope, description
147
+
148
+
149
+ def generate_message(
150
+ commit_type: str,
151
+ scope: Optional[str],
152
+ subject: str,
153
+ body: Optional[str] = None,
154
+ footer: Optional[str] = None
155
+ ) -> str:
156
+ """
157
+ Generate a conventional commit message.
158
+
159
+ Args:
160
+ commit_type: Type of commit (feat, fix, docs, etc.)
161
+ scope: Optional scope of the change
162
+ subject: Brief description of the change
163
+ body: Optional detailed body
164
+ footer: Optional footer (e.g., Closes #123)
165
+
166
+ Returns:
167
+ Formatted conventional commit message
168
+ """
169
+ # Build the subject line
170
+ if scope:
171
+ subject_line = f"{commit_type}({scope}): {subject}"
172
+ else:
173
+ subject_line = f"{commit_type}: {subject}"
174
+
175
+ # Ensure subject starts with lowercase
176
+ parts = subject_line.split(': ', 1)
177
+ if len(parts) == 2:
178
+ subject_line = f"{parts[0]}: {parts[1][0].lower()}{parts[1][1:] if len(parts[1]) > 1 else ''}"
179
+
180
+ # Build full message
181
+ message = subject_line
182
+
183
+ if body:
184
+ message += f"\n\n{body}"
185
+
186
+ if footer:
187
+ message += f"\n\n{footer}"
188
+
189
+ return message
190
+
191
+
192
+ def main():
193
+ """Main entry point for the commit message generation script."""
194
+ parser = argparse.ArgumentParser(
195
+ description="Generate conventional commit messages based on code diffs",
196
+ formatter_class=argparse.RawDescriptionHelpFormatter,
197
+ epilog="""
198
+ Examples:
199
+ # Generate from staged changes
200
+ %(prog)s --staged
201
+
202
+ # Generate from unstaged changes
203
+ %(prog)s --unstaged
204
+
205
+ # Generate from a diff file
206
+ %(prog)s --file changes.diff
207
+
208
+ # Generate with custom subject
209
+ %(prog)s --staged --subject "implement new authentication"
210
+
211
+ # Output as JSON
212
+ %(prog)s --staged --format json
213
+ """
214
+ )
215
+
216
+ input_group = parser.add_mutually_exclusive_group()
217
+ input_group.add_argument(
218
+ '--staged',
219
+ action='store_true',
220
+ help='Analyze staged changes (default)'
221
+ )
222
+ input_group.add_argument(
223
+ '--unstaged',
224
+ action='store_true',
225
+ help='Analyze unstaged changes'
226
+ )
227
+ input_group.add_argument(
228
+ '--file',
229
+ type=str,
230
+ help='Path to diff file'
231
+ )
232
+
233
+ parser.add_argument(
234
+ '--subject',
235
+ type=str,
236
+ help='Custom subject for the commit message'
237
+ )
238
+ parser.add_argument(
239
+ '--body',
240
+ type=str,
241
+ help='Optional body text'
242
+ )
243
+ parser.add_argument(
244
+ '--footer',
245
+ type=str,
246
+ help='Optional footer (e.g., Closes #123)'
247
+ )
248
+ parser.add_argument(
249
+ '--format',
250
+ choices=['text', 'json'],
251
+ default='text',
252
+ help='Output format (default: text)'
253
+ )
254
+ parser.add_argument(
255
+ '-v', '--verbose',
256
+ action='store_true',
257
+ help='Enable verbose output'
258
+ )
259
+
260
+ args = parser.parse_args()
261
+
262
+ # Get diff content
263
+ if args.file:
264
+ diff_content = get_diff_from_file(args.file)
265
+ elif args.unstaged:
266
+ diff_content = get_git_diff(staged_only=False)
267
+ else: # Default to staged
268
+ diff_content = get_git_diff(staged_only=True)
269
+
270
+ if not diff_content:
271
+ print("Error: No changes to analyze", file=sys.stderr)
272
+ return 1
273
+
274
+ # Analyze the diff
275
+ commit_type, scope, _ = analyze_diff(diff_content)
276
+
277
+ # Use custom subject if provided
278
+ subject = args.subject or "update code"
279
+
280
+ # Generate message
281
+ message = generate_message(
282
+ commit_type,
283
+ scope if scope else None,
284
+ subject,
285
+ args.body,
286
+ args.footer
287
+ )
288
+
289
+ # Output result
290
+ if args.format == 'json':
291
+ output = {
292
+ 'type': commit_type,
293
+ 'scope': scope or None,
294
+ 'subject': subject,
295
+ 'body': args.body,
296
+ 'footer': args.footer,
297
+ 'message': message
298
+ }
299
+ print(json.dumps(output, indent=2))
300
+ else:
301
+ print(message)
302
+
303
+ return 0
304
+
305
+
306
+ if __name__ == '__main__':
307
+ sys.exit(main())