devopsdriver 0.1.46__tar.gz → 0.1.49__tar.gz
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.
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/PKG-INFO +26 -15
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/README.md +20 -10
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/__init__.py +2 -2
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/__init__.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/azureobject.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/builds/build.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/builds/client.py +2 -2
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/clients.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/pipeline/client.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/pipeline/log.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/pipeline/pipeline.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/pipeline/run.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/timestamp.py +1 -1
- devopsdriver-0.1.49/devopsdriver/azdo/workitem/__init__.py +1 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/workitem/client.py +2 -2
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/workitem/wiql.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/dataobject.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/manage_settings.py +10 -3
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/sendmail.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/settings.py +96 -81
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/template.py +1 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/PKG-INFO +26 -15
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/requires.txt +3 -3
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/pyproject.toml +26 -27
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_settings.py +40 -6
- devopsdriver-0.1.46/devopsdriver/azdo/workitem/__init__.py +0 -1
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/LICENSE +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/builds/__init__.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/azdo/pipeline/__init__.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver/templates/manage_settings.txt.mako +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/SOURCES.txt +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/dependency_links.txt +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/entry_points.txt +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/devopsdriver.egg-info/top_level.txt +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/setup.cfg +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_azureobject.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_build.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_build_client.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_clients.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_pipeline.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_pipeline_client.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_pipeline_run.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_timestamp.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_workitem_client.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_azure_workitem_wiql.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_dataobject.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_manage_settings.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_sendmail.py +0 -0
- {devopsdriver-0.1.46 → devopsdriver-0.1.49}/tests/test_template.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: devopsdriver
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.49
|
|
4
4
|
Summary: DevOps tools
|
|
5
5
|
Author-email: Marc Page <marcallenpage@gmail.com>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -47,10 +47,10 @@ Requires-Python: >=3.10
|
|
|
47
47
|
Description-Content-Type: text/markdown
|
|
48
48
|
License-File: LICENSE
|
|
49
49
|
Requires-Dist: PyYAML==6.0.2
|
|
50
|
-
Requires-Dist: keyring==25.
|
|
51
|
-
Requires-Dist: setuptools==
|
|
50
|
+
Requires-Dist: keyring==25.6.0
|
|
51
|
+
Requires-Dist: setuptools==75.8.0
|
|
52
52
|
Requires-Dist: azure-devops==7.1.0b4
|
|
53
|
-
Requires-Dist: Mako==1.3.
|
|
53
|
+
Requires-Dist: Mako==1.3.10
|
|
54
54
|
Provides-Extra: dev
|
|
55
55
|
Requires-Dist: black>=24.3.0; extra == "dev"
|
|
56
56
|
Requires-Dist: pylint>=3.1.0; extra == "dev"
|
|
@@ -58,9 +58,12 @@ Provides-Extra: test
|
|
|
58
58
|
Requires-Dist: pytest>=8.1.1; extra == "test"
|
|
59
59
|
Requires-Dist: coverage>=7.4.4; extra == "test"
|
|
60
60
|
Provides-Extra: doc
|
|
61
|
+
Dynamic: license-file
|
|
62
|
+
|
|
63
|
+
# devops-driver
|
|
61
64
|
|
|
62
65
|

|
|
63
|
-
[](https://pypi.org/project/devopsdriver/0.1.49/)
|
|
64
67
|
[](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
|
|
65
68
|
[](https://github.com/marcpage/devops-driver/graphs/contributors)
|
|
66
69
|
[](http://makeapullrequest.com)
|
|
@@ -82,13 +85,11 @@ Provides-Extra: doc
|
|
|
82
85
|
[](https://azure.microsoft.com/)
|
|
83
86
|
[](https://gmail.com/)
|
|
84
87
|
|
|
85
|
-
OS:
|
|
88
|
+
OS:
|
|
86
89
|
[](https://microsoft.com/)
|
|
87
90
|
[](https://apple.com/)
|
|
88
91
|
[](https://linux.org/)
|
|
89
92
|
|
|
90
|
-
# devops-driver
|
|
91
|
-
|
|
92
93
|
Devops-driver is a collection of tools to help streamline developer's experience and gain insights into various processes.
|
|
93
94
|
|
|
94
95
|
## Tools
|
|
@@ -107,6 +108,7 @@ To allow seamless work in both pipelines as well as in the development environme
|
|
|
107
108
|
Say you want a pipeline that looks for User Stories that are newer than 3 days and send out an email.
|
|
108
109
|
|
|
109
110
|
### \<platform dependent path\>/devopsdriver.yml
|
|
111
|
+
|
|
110
112
|
```yaml
|
|
111
113
|
smtp:
|
|
112
114
|
sender: JohnDoe@company.com
|
|
@@ -116,7 +118,7 @@ secrets:
|
|
|
116
118
|
smtp.password: smtp/password
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
121
|
+
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
120
122
|
|
|
121
123
|
| Platform | Global Directory |
|
|
122
124
|
|----------|------------------------|
|
|
@@ -127,6 +129,7 @@ This file is in a global place (location varies by OS) and stores information th
|
|
|
127
129
|
The `secrets` are extra sensative and are stored in the OS keychain.
|
|
128
130
|
|
|
129
131
|
### Set secrets in the keychain
|
|
132
|
+
|
|
130
133
|
```bash
|
|
131
134
|
$ python3 -m venv .venv
|
|
132
135
|
$ source .venv/bin/activate
|
|
@@ -138,16 +141,21 @@ secret: azure.token key: azure/token
|
|
|
138
141
|
smtp.password (azure/token): ****
|
|
139
142
|
$ settings --secrets
|
|
140
143
|
secret: azure.token key: azure/token
|
|
141
|
-
|
|
144
|
+
Value set
|
|
142
145
|
secret: smtp.password key: smtp/password
|
|
143
|
-
|
|
146
|
+
Value set
|
|
144
147
|
$
|
|
145
148
|
```
|
|
149
|
+
|
|
146
150
|
The first call to `settings` will look for every secret and check if they are already set in the keychain.
|
|
147
151
|
For any secret that has not been set in the keychain, you will be prompted to enter the password to store.
|
|
148
152
|
The second call to `settings` will verify that all the values have been set in the keychain.
|
|
149
153
|
|
|
154
|
+
**Note**: If your `secrets`, `cli`, or `env` are in a yaml file named after your script,
|
|
155
|
+
you can call `settings --secrets --script my_script.py`.
|
|
156
|
+
|
|
150
157
|
### devopsdriver.yml
|
|
158
|
+
|
|
151
159
|
```yaml
|
|
152
160
|
azure:
|
|
153
161
|
url: https://dev.azure.com/MyCompany
|
|
@@ -173,15 +181,18 @@ The `cli` and `env` map command line switches and environment variables to those
|
|
|
173
181
|
This allows for many options for setting values depending on your needs.
|
|
174
182
|
|
|
175
183
|
### new_stories.yml
|
|
184
|
+
|
|
176
185
|
```yaml
|
|
177
186
|
scrum masters:
|
|
178
187
|
- JohnDoe@company.com
|
|
179
188
|
- JaneDoe@company.com
|
|
180
189
|
```
|
|
190
|
+
|
|
181
191
|
This file is specific to your script and not shared.
|
|
182
192
|
These are values that you want to use in your script but have them here for easy adjustment.
|
|
183
193
|
|
|
184
194
|
### new_stories.html.mako
|
|
195
|
+
|
|
185
196
|
```html
|
|
186
197
|
<h1>Stories created in the last ${days} days</h1>
|
|
187
198
|
<ul>
|
|
@@ -194,6 +205,7 @@ These are values that you want to use in your script but have them here for easy
|
|
|
194
205
|
This file is the template for the email body.
|
|
195
206
|
|
|
196
207
|
### new_stories.py
|
|
208
|
+
|
|
197
209
|
```python
|
|
198
210
|
from datetime import date, timedelta
|
|
199
211
|
|
|
@@ -229,9 +241,9 @@ send_email(
|
|
|
229
241
|
|
|
230
242
|
### The email sent
|
|
231
243
|
|
|
232
|
-
**From**: JohnDoe@company.com
|
|
244
|
+
**From**: `JohnDoe@company.com`
|
|
233
245
|
|
|
234
|
-
**To**: JohnDoe@company.com
|
|
246
|
+
**To**: `JohnDoe@company.com`, `JaneDoe@company.com`
|
|
235
247
|
|
|
236
248
|
**Subject**: Stories created in the last 3 days
|
|
237
249
|
|
|
@@ -246,4 +258,3 @@ send_email(
|
|
|
246
258
|
- 754 frontend - store to schema
|
|
247
259
|
- 755 Transfer job to production. Setup migrations to move to production
|
|
248
260
|
- 756 Query subscription status from App
|
|
249
|
-
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
# devops-driver
|
|
2
|
+
|
|
1
3
|

|
|
2
|
-
[](https://pypi.org/project/devopsdriver/0.1.49/)
|
|
3
5
|
[](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
|
|
4
6
|
[](https://github.com/marcpage/devops-driver/graphs/contributors)
|
|
5
7
|
[](http://makeapullrequest.com)
|
|
@@ -21,13 +23,11 @@
|
|
|
21
23
|
[](https://azure.microsoft.com/)
|
|
22
24
|
[](https://gmail.com/)
|
|
23
25
|
|
|
24
|
-
OS:
|
|
26
|
+
OS:
|
|
25
27
|
[](https://microsoft.com/)
|
|
26
28
|
[](https://apple.com/)
|
|
27
29
|
[](https://linux.org/)
|
|
28
30
|
|
|
29
|
-
# devops-driver
|
|
30
|
-
|
|
31
31
|
Devops-driver is a collection of tools to help streamline developer's experience and gain insights into various processes.
|
|
32
32
|
|
|
33
33
|
## Tools
|
|
@@ -46,6 +46,7 @@ To allow seamless work in both pipelines as well as in the development environme
|
|
|
46
46
|
Say you want a pipeline that looks for User Stories that are newer than 3 days and send out an email.
|
|
47
47
|
|
|
48
48
|
### \<platform dependent path\>/devopsdriver.yml
|
|
49
|
+
|
|
49
50
|
```yaml
|
|
50
51
|
smtp:
|
|
51
52
|
sender: JohnDoe@company.com
|
|
@@ -55,7 +56,7 @@ secrets:
|
|
|
55
56
|
smtp.password: smtp/password
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
59
|
+
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
59
60
|
|
|
60
61
|
| Platform | Global Directory |
|
|
61
62
|
|----------|------------------------|
|
|
@@ -66,6 +67,7 @@ This file is in a global place (location varies by OS) and stores information th
|
|
|
66
67
|
The `secrets` are extra sensative and are stored in the OS keychain.
|
|
67
68
|
|
|
68
69
|
### Set secrets in the keychain
|
|
70
|
+
|
|
69
71
|
```bash
|
|
70
72
|
$ python3 -m venv .venv
|
|
71
73
|
$ source .venv/bin/activate
|
|
@@ -77,16 +79,21 @@ secret: azure.token key: azure/token
|
|
|
77
79
|
smtp.password (azure/token): ****
|
|
78
80
|
$ settings --secrets
|
|
79
81
|
secret: azure.token key: azure/token
|
|
80
|
-
|
|
82
|
+
Value set
|
|
81
83
|
secret: smtp.password key: smtp/password
|
|
82
|
-
|
|
84
|
+
Value set
|
|
83
85
|
$
|
|
84
86
|
```
|
|
87
|
+
|
|
85
88
|
The first call to `settings` will look for every secret and check if they are already set in the keychain.
|
|
86
89
|
For any secret that has not been set in the keychain, you will be prompted to enter the password to store.
|
|
87
90
|
The second call to `settings` will verify that all the values have been set in the keychain.
|
|
88
91
|
|
|
92
|
+
**Note**: If your `secrets`, `cli`, or `env` are in a yaml file named after your script,
|
|
93
|
+
you can call `settings --secrets --script my_script.py`.
|
|
94
|
+
|
|
89
95
|
### devopsdriver.yml
|
|
96
|
+
|
|
90
97
|
```yaml
|
|
91
98
|
azure:
|
|
92
99
|
url: https://dev.azure.com/MyCompany
|
|
@@ -112,15 +119,18 @@ The `cli` and `env` map command line switches and environment variables to those
|
|
|
112
119
|
This allows for many options for setting values depending on your needs.
|
|
113
120
|
|
|
114
121
|
### new_stories.yml
|
|
122
|
+
|
|
115
123
|
```yaml
|
|
116
124
|
scrum masters:
|
|
117
125
|
- JohnDoe@company.com
|
|
118
126
|
- JaneDoe@company.com
|
|
119
127
|
```
|
|
128
|
+
|
|
120
129
|
This file is specific to your script and not shared.
|
|
121
130
|
These are values that you want to use in your script but have them here for easy adjustment.
|
|
122
131
|
|
|
123
132
|
### new_stories.html.mako
|
|
133
|
+
|
|
124
134
|
```html
|
|
125
135
|
<h1>Stories created in the last ${days} days</h1>
|
|
126
136
|
<ul>
|
|
@@ -133,6 +143,7 @@ These are values that you want to use in your script but have them here for easy
|
|
|
133
143
|
This file is the template for the email body.
|
|
134
144
|
|
|
135
145
|
### new_stories.py
|
|
146
|
+
|
|
136
147
|
```python
|
|
137
148
|
from datetime import date, timedelta
|
|
138
149
|
|
|
@@ -168,9 +179,9 @@ send_email(
|
|
|
168
179
|
|
|
169
180
|
### The email sent
|
|
170
181
|
|
|
171
|
-
**From**: JohnDoe@company.com
|
|
182
|
+
**From**: `JohnDoe@company.com`
|
|
172
183
|
|
|
173
|
-
**To**: JohnDoe@company.com
|
|
184
|
+
**To**: `JohnDoe@company.com`, `JaneDoe@company.com`
|
|
174
185
|
|
|
175
186
|
**Subject**: Stories created in the last 3 days
|
|
176
187
|
|
|
@@ -185,4 +196,3 @@ send_email(
|
|
|
185
196
|
- 754 frontend - store to schema
|
|
186
197
|
- 755 Transfer job to production. Setup migrations to move to production
|
|
187
198
|
- 756 Query subscription status from App
|
|
188
|
-
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""DevOps tools"""
|
|
2
2
|
|
|
3
3
|
from .settings import Settings
|
|
4
4
|
from .sendmail import send_email
|
|
@@ -6,6 +6,6 @@ from .template import Template
|
|
|
6
6
|
from .azdo.clients import Azure
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
__version__ = "0.1.
|
|
9
|
+
__version__ = "0.1.49"
|
|
10
10
|
__author__ = "Marc Page"
|
|
11
11
|
__credits__ = ""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""
|
|
4
|
+
"""Azure Build Client"""
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
from datetime import datetime
|
|
@@ -16,7 +16,7 @@ class Client: # pylint: disable=too-few-public-methods
|
|
|
16
16
|
def __init__(self, client: BuildClient):
|
|
17
17
|
self.client = client
|
|
18
18
|
|
|
19
|
-
def list( # pylint: disable=too-many-arguments
|
|
19
|
+
def list( # pylint: disable=too-many-positional-arguments,too-many-arguments
|
|
20
20
|
self,
|
|
21
21
|
project: str,
|
|
22
22
|
pipelines: list[int] = None,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""init workitem module"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""
|
|
4
|
+
"""Azure WorkItem Client"""
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
from azure.devops.v7_1.work_item_tracking.models import Wiql as AzureWiql
|
|
@@ -43,7 +43,7 @@ class Client:
|
|
|
43
43
|
top=top,
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
def get_history( # pylint: disable=too-many-arguments
|
|
46
|
+
def get_history( # pylint: disable=too-many-positional-arguments,too-many-arguments
|
|
47
47
|
self,
|
|
48
48
|
wi_id: int,
|
|
49
49
|
project: str = None,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""
|
|
4
|
+
"""Module Doc"""
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
from os.path import dirname, join
|
|
7
|
+
from os.path import dirname, join, abspath
|
|
8
8
|
from sys import argv as sys_argv
|
|
9
9
|
from getpass import getpass as os_getpass
|
|
10
10
|
|
|
@@ -31,7 +31,14 @@ def main() -> None:
|
|
|
31
31
|
)
|
|
32
32
|
return
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
position = args.index("--script") if "--script" in args else len(args)
|
|
35
|
+
script = __file__
|
|
36
|
+
|
|
37
|
+
if position + 1 < len(args):
|
|
38
|
+
args.pop(position)
|
|
39
|
+
script = abspath(args.pop(position))
|
|
40
|
+
|
|
41
|
+
settings = Settings(script, dirname(dirname(__file__))).key("secrets")
|
|
35
42
|
|
|
36
43
|
if "--secrets" in args:
|
|
37
44
|
args.remove("--secrets")
|
|
@@ -1,78 +1,78 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
4
|
+
"""Settings that can be in files, environment, or on the command line
|
|
5
|
+
|
|
6
|
+
Settings can be set on the command line, environment, in the code, or in files.
|
|
7
|
+
|
|
8
|
+
Priority order:
|
|
9
|
+
- in code
|
|
10
|
+
- command line
|
|
11
|
+
- environment
|
|
12
|
+
- files
|
|
13
|
+
|
|
14
|
+
Files can be JSON or YAML.
|
|
15
|
+
They must have .json, .yml, or .yaml extension.
|
|
16
|
+
Files can be named after the file passed in (__file__) or "devopsdriver".
|
|
17
|
+
All files named after the file passed in have priority over "devopsdriver".
|
|
18
|
+
This allows for shared settings for multiple scripts as well as specific settings.
|
|
19
|
+
Files can be in an OS-specific preferences location, a series of specified directories,
|
|
20
|
+
or next to the file passed in (__file__).
|
|
21
|
+
This allows for secrets, keys, and tokens to be stored on the machine and not in the repo.
|
|
22
|
+
|
|
23
|
+
Files in the OS specific directories have priority over other files and are stored in:
|
|
24
|
+
- macOS: ~/Library/Preferences/
|
|
25
|
+
- Windows: %APPDATA%/
|
|
26
|
+
- Linux: ~/.devopsdriver/
|
|
27
|
+
|
|
28
|
+
You can have environment variable substitutions in the values in the files.
|
|
29
|
+
For instance, you can specify:
|
|
30
|
+
|
|
31
|
+
output: ${home}/reports
|
|
32
|
+
|
|
33
|
+
The `${home}` will be replaced with the value of the HOME environment variable, if it exists.
|
|
34
|
+
If the environment variable does not exist, no change is made.
|
|
35
|
+
|
|
36
|
+
Use case 1: Secrets not in repo
|
|
37
|
+
tokens, passwords, etc can be stored in <pref>/devopsdriver.yml
|
|
38
|
+
This will allow for all scripts to access those secrets
|
|
39
|
+
but they are not in the repo.
|
|
40
|
+
For pipeline runs these secrets can be passed on the command line or in the environment.
|
|
41
|
+
|
|
42
|
+
Use case 2: common settings among scripts
|
|
43
|
+
Store your common settings in devopsdriver.yml next to your script.
|
|
44
|
+
All scripts in this directory will have access to these settings.
|
|
45
|
+
For instance, say you want all emails sent from the same person.
|
|
46
|
+
You could set 'email: me@domain.com' in devopsdriver.html.
|
|
47
|
+
You could also, store report paths, emails, groups, holidays, etc.
|
|
48
|
+
Any data all scripts may want to have access to.
|
|
49
|
+
|
|
50
|
+
Use case 3: configurable settings
|
|
51
|
+
Any settings in your script that you may want to configure.
|
|
52
|
+
If your script is `cool_script.py` then put the settings in `cool_script.yml` next to it.
|
|
53
|
+
This could be colors, emails, repos, queries, whatever.
|
|
54
|
+
|
|
55
|
+
Use case 4: override secrets for specific script
|
|
56
|
+
Overriding secrets stored in `<pref>/devopsdriver.yml` for specific scripts.
|
|
57
|
+
If your script is `cool_script.py` save them to `<pref>/cool_script.yml`.
|
|
58
|
+
|
|
59
|
+
*Note*: You can override a specific setting in a sub-dictionary.
|
|
60
|
+
For instance, say `<pref>/devopsdriver.yml`:
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
api:
|
|
64
|
+
user: johndoe
|
|
65
|
+
password: Setec Astronomy
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You could override this for `cool_script.py` be adding `<pref>/cool_script.yml`:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
api:
|
|
72
|
+
user: janedoe
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
johndoe and janedoe share the same password, so you just need to update the `user`
|
|
76
76
|
"""
|
|
77
77
|
|
|
78
78
|
|
|
@@ -143,19 +143,29 @@ class Settings:
|
|
|
143
143
|
PREF_DIR = {
|
|
144
144
|
"Darwin": join(ENVIRON.get("HOME", ""), "Library", "Preferences"),
|
|
145
145
|
"Windows": join(ENVIRON.get("APPDATA", "")),
|
|
146
|
-
"Linux": join(ENVIRON.get("HOME", ""), "
|
|
146
|
+
"Linux": join(ENVIRON.get("HOME", ""), ".%shared_name%"),
|
|
147
147
|
}
|
|
148
148
|
ENV_VAR_PATTERN = regex(r"\${(\S+)}")
|
|
149
149
|
|
|
150
|
-
def __init__(self, file: str, *directories, **settings):
|
|
150
|
+
def __init__(self, file: str, *directories, shared_name: str = None, **settings):
|
|
151
151
|
"""Create a settings object using a file, directories to search, and settings overrides
|
|
152
152
|
|
|
153
153
|
Args:
|
|
154
154
|
file (str): The basename to use and a directory to search. pass __file__
|
|
155
|
+
*directories (list[str]): You can pass other directories to search for files
|
|
156
|
+
shared_name (str, optional): The name of the common settings file.
|
|
157
|
+
Defaults to "devopsdriver".
|
|
158
|
+
**settings (dict[str,str]): Keys you want to directly override in the code
|
|
155
159
|
"""
|
|
156
160
|
self.overrides = settings
|
|
157
|
-
directories = [
|
|
158
|
-
|
|
161
|
+
directories = [
|
|
162
|
+
Settings.__preferences_dir(SHARED if shared_name is None else shared_name),
|
|
163
|
+
dirname(file),
|
|
164
|
+
*directories,
|
|
165
|
+
]
|
|
166
|
+
search_info = Settings.__all_paths(
|
|
167
|
+
file, directories, SHARED if shared_name is None else shared_name
|
|
168
|
+
)
|
|
159
169
|
self.search_files = [join(d, n + e) for e, n, d, _ in search_info]
|
|
160
170
|
self.settings = Settings.__find_all_settings(search_info)
|
|
161
171
|
self.opts = {}
|
|
@@ -316,9 +326,14 @@ class Settings:
|
|
|
316
326
|
return self.get(key)
|
|
317
327
|
|
|
318
328
|
@staticmethod
|
|
319
|
-
def __preferences_dir() -> str:
|
|
320
|
-
|
|
321
|
-
|
|
329
|
+
def __preferences_dir(shared_name: str) -> str:
|
|
330
|
+
|
|
331
|
+
default_dir = Settings.PREF_DIR[Settings.DEFAULT_PREF_DIR].replace(
|
|
332
|
+
"%shared_name%", shared_name
|
|
333
|
+
)
|
|
334
|
+
directory = Settings.PREF_DIR.get(SYSTEM(), default_dir).replace(
|
|
335
|
+
"%shared_name%", shared_name
|
|
336
|
+
)
|
|
322
337
|
MAKEDIRS(directory, exist_ok=True)
|
|
323
338
|
return directory
|
|
324
339
|
|
|
@@ -341,8 +356,8 @@ class Settings:
|
|
|
341
356
|
Settings.__merge(base[key], new[key])
|
|
342
357
|
|
|
343
358
|
@staticmethod
|
|
344
|
-
def __all_paths(file: str, directories: list[str]) -> list[tuple]:
|
|
345
|
-
names = [splitext(basename(file))[0],
|
|
359
|
+
def __all_paths(file: str, directories: list[str], shared: str) -> list[tuple]:
|
|
360
|
+
names = [splitext(basename(file))[0], shared]
|
|
346
361
|
return [
|
|
347
362
|
(e, n, d, f)
|
|
348
363
|
for n in names
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: devopsdriver
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.49
|
|
4
4
|
Summary: DevOps tools
|
|
5
5
|
Author-email: Marc Page <marcallenpage@gmail.com>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -47,10 +47,10 @@ Requires-Python: >=3.10
|
|
|
47
47
|
Description-Content-Type: text/markdown
|
|
48
48
|
License-File: LICENSE
|
|
49
49
|
Requires-Dist: PyYAML==6.0.2
|
|
50
|
-
Requires-Dist: keyring==25.
|
|
51
|
-
Requires-Dist: setuptools==
|
|
50
|
+
Requires-Dist: keyring==25.6.0
|
|
51
|
+
Requires-Dist: setuptools==75.8.0
|
|
52
52
|
Requires-Dist: azure-devops==7.1.0b4
|
|
53
|
-
Requires-Dist: Mako==1.3.
|
|
53
|
+
Requires-Dist: Mako==1.3.10
|
|
54
54
|
Provides-Extra: dev
|
|
55
55
|
Requires-Dist: black>=24.3.0; extra == "dev"
|
|
56
56
|
Requires-Dist: pylint>=3.1.0; extra == "dev"
|
|
@@ -58,9 +58,12 @@ Provides-Extra: test
|
|
|
58
58
|
Requires-Dist: pytest>=8.1.1; extra == "test"
|
|
59
59
|
Requires-Dist: coverage>=7.4.4; extra == "test"
|
|
60
60
|
Provides-Extra: doc
|
|
61
|
+
Dynamic: license-file
|
|
62
|
+
|
|
63
|
+
# devops-driver
|
|
61
64
|
|
|
62
65
|

|
|
63
|
-
[](https://pypi.org/project/devopsdriver/0.1.49/)
|
|
64
67
|
[](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
|
|
65
68
|
[](https://github.com/marcpage/devops-driver/graphs/contributors)
|
|
66
69
|
[](http://makeapullrequest.com)
|
|
@@ -82,13 +85,11 @@ Provides-Extra: doc
|
|
|
82
85
|
[](https://azure.microsoft.com/)
|
|
83
86
|
[](https://gmail.com/)
|
|
84
87
|
|
|
85
|
-
OS:
|
|
88
|
+
OS:
|
|
86
89
|
[](https://microsoft.com/)
|
|
87
90
|
[](https://apple.com/)
|
|
88
91
|
[](https://linux.org/)
|
|
89
92
|
|
|
90
|
-
# devops-driver
|
|
91
|
-
|
|
92
93
|
Devops-driver is a collection of tools to help streamline developer's experience and gain insights into various processes.
|
|
93
94
|
|
|
94
95
|
## Tools
|
|
@@ -107,6 +108,7 @@ To allow seamless work in both pipelines as well as in the development environme
|
|
|
107
108
|
Say you want a pipeline that looks for User Stories that are newer than 3 days and send out an email.
|
|
108
109
|
|
|
109
110
|
### \<platform dependent path\>/devopsdriver.yml
|
|
111
|
+
|
|
110
112
|
```yaml
|
|
111
113
|
smtp:
|
|
112
114
|
sender: JohnDoe@company.com
|
|
@@ -116,7 +118,7 @@ secrets:
|
|
|
116
118
|
smtp.password: smtp/password
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
121
|
+
This file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development.
|
|
120
122
|
|
|
121
123
|
| Platform | Global Directory |
|
|
122
124
|
|----------|------------------------|
|
|
@@ -127,6 +129,7 @@ This file is in a global place (location varies by OS) and stores information th
|
|
|
127
129
|
The `secrets` are extra sensative and are stored in the OS keychain.
|
|
128
130
|
|
|
129
131
|
### Set secrets in the keychain
|
|
132
|
+
|
|
130
133
|
```bash
|
|
131
134
|
$ python3 -m venv .venv
|
|
132
135
|
$ source .venv/bin/activate
|
|
@@ -138,16 +141,21 @@ secret: azure.token key: azure/token
|
|
|
138
141
|
smtp.password (azure/token): ****
|
|
139
142
|
$ settings --secrets
|
|
140
143
|
secret: azure.token key: azure/token
|
|
141
|
-
|
|
144
|
+
Value set
|
|
142
145
|
secret: smtp.password key: smtp/password
|
|
143
|
-
|
|
146
|
+
Value set
|
|
144
147
|
$
|
|
145
148
|
```
|
|
149
|
+
|
|
146
150
|
The first call to `settings` will look for every secret and check if they are already set in the keychain.
|
|
147
151
|
For any secret that has not been set in the keychain, you will be prompted to enter the password to store.
|
|
148
152
|
The second call to `settings` will verify that all the values have been set in the keychain.
|
|
149
153
|
|
|
154
|
+
**Note**: If your `secrets`, `cli`, or `env` are in a yaml file named after your script,
|
|
155
|
+
you can call `settings --secrets --script my_script.py`.
|
|
156
|
+
|
|
150
157
|
### devopsdriver.yml
|
|
158
|
+
|
|
151
159
|
```yaml
|
|
152
160
|
azure:
|
|
153
161
|
url: https://dev.azure.com/MyCompany
|
|
@@ -173,15 +181,18 @@ The `cli` and `env` map command line switches and environment variables to those
|
|
|
173
181
|
This allows for many options for setting values depending on your needs.
|
|
174
182
|
|
|
175
183
|
### new_stories.yml
|
|
184
|
+
|
|
176
185
|
```yaml
|
|
177
186
|
scrum masters:
|
|
178
187
|
- JohnDoe@company.com
|
|
179
188
|
- JaneDoe@company.com
|
|
180
189
|
```
|
|
190
|
+
|
|
181
191
|
This file is specific to your script and not shared.
|
|
182
192
|
These are values that you want to use in your script but have them here for easy adjustment.
|
|
183
193
|
|
|
184
194
|
### new_stories.html.mako
|
|
195
|
+
|
|
185
196
|
```html
|
|
186
197
|
<h1>Stories created in the last ${days} days</h1>
|
|
187
198
|
<ul>
|
|
@@ -194,6 +205,7 @@ These are values that you want to use in your script but have them here for easy
|
|
|
194
205
|
This file is the template for the email body.
|
|
195
206
|
|
|
196
207
|
### new_stories.py
|
|
208
|
+
|
|
197
209
|
```python
|
|
198
210
|
from datetime import date, timedelta
|
|
199
211
|
|
|
@@ -229,9 +241,9 @@ send_email(
|
|
|
229
241
|
|
|
230
242
|
### The email sent
|
|
231
243
|
|
|
232
|
-
**From**: JohnDoe@company.com
|
|
244
|
+
**From**: `JohnDoe@company.com`
|
|
233
245
|
|
|
234
|
-
**To**: JohnDoe@company.com
|
|
246
|
+
**To**: `JohnDoe@company.com`, `JaneDoe@company.com`
|
|
235
247
|
|
|
236
248
|
**Subject**: Stories created in the last 3 days
|
|
237
249
|
|
|
@@ -246,4 +258,3 @@ send_email(
|
|
|
246
258
|
- 754 frontend - store to schema
|
|
247
259
|
- 755 Transfer job to production. Setup migrations to move to production
|
|
248
260
|
- 756 Query subscription status from App
|
|
249
|
-
|
|
@@ -2,31 +2,37 @@
|
|
|
2
2
|
name = "devopsdriver"
|
|
3
3
|
description = "DevOps tools"
|
|
4
4
|
readme = "README.md"
|
|
5
|
-
license = {file = "LICENSE"}
|
|
5
|
+
license = { file = "LICENSE" }
|
|
6
6
|
dynamic = ["version"]
|
|
7
7
|
requires-python = ">= 3.10"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"PyYAML==6.0.2",
|
|
10
|
-
"keyring==25.
|
|
11
|
-
"setuptools==
|
|
10
|
+
"keyring==25.6.0",
|
|
11
|
+
"setuptools==75.8.0", # neded for azure-devops to use 7.1 API
|
|
12
12
|
"azure-devops==7.1.0b4",
|
|
13
|
-
"Mako==1.3.
|
|
13
|
+
"Mako==1.3.10",
|
|
14
14
|
]
|
|
15
|
-
keywords = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"Programming Language :: Python :: 3.10",
|
|
24
|
-
"Topic :: Utilities",
|
|
25
|
-
"Topic :: Software Development",
|
|
15
|
+
keywords = [
|
|
16
|
+
"azure",
|
|
17
|
+
"devops",
|
|
18
|
+
"jira",
|
|
19
|
+
"confluence",
|
|
20
|
+
"email",
|
|
21
|
+
"pipelines",
|
|
22
|
+
"tools",
|
|
26
23
|
]
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 1 - Planning",
|
|
26
|
+
"Environment :: Console",
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"Programming Language :: Python",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"License :: OSI Approved :: The Unlicense (Unlicense)",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Topic :: Utilities",
|
|
33
|
+
"Topic :: Software Development",
|
|
29
34
|
]
|
|
35
|
+
authors = [{ name = "Marc Page", email = "marcallenpage@gmail.com" }]
|
|
30
36
|
|
|
31
37
|
[project.scripts]
|
|
32
38
|
settings = "devopsdriver.manage_settings:main"
|
|
@@ -38,14 +44,8 @@ settings = "devopsdriver.manage_settings:main"
|
|
|
38
44
|
include = ["devopsdriver*"]
|
|
39
45
|
|
|
40
46
|
[project.optional-dependencies]
|
|
41
|
-
dev = [
|
|
42
|
-
|
|
43
|
-
"pylint>=3.1.0",
|
|
44
|
-
]
|
|
45
|
-
test = [
|
|
46
|
-
"pytest>=8.1.1",
|
|
47
|
-
"coverage>=7.4.4",
|
|
48
|
-
]
|
|
47
|
+
dev = ["black>=24.3.0", "pylint>=3.1.0"]
|
|
48
|
+
test = ["pytest>=8.1.1", "coverage>=7.4.4"]
|
|
49
49
|
doc = []
|
|
50
50
|
|
|
51
51
|
[project.urls]
|
|
@@ -56,9 +56,8 @@ Issues = "https://github.com/marcpage/devops-driver/issues"
|
|
|
56
56
|
Changelog = "https://github.com/marcpage/devops-driver/releases"
|
|
57
57
|
|
|
58
58
|
[tool.setuptools.dynamic]
|
|
59
|
-
version = {attr = "devopsdriver.__version__"}
|
|
59
|
+
version = { attr = "devopsdriver.__version__" }
|
|
60
60
|
|
|
61
61
|
[build-system]
|
|
62
62
|
requires = ["setuptools >= 69.2"]
|
|
63
63
|
build-backend = "setuptools.build_meta"
|
|
64
|
-
|
|
@@ -98,6 +98,40 @@ def test_basic():
|
|
|
98
98
|
.env("yy", "yota")
|
|
99
99
|
)
|
|
100
100
|
ltr = {"Linux": "l", "Darwin": "m", "Windows": "w", "Unknown": "l"}
|
|
101
|
+
local_overrides = {
|
|
102
|
+
"Darwin": {
|
|
103
|
+
"v": "mmv",
|
|
104
|
+
"dp.v": "mmv",
|
|
105
|
+
"w": "mmw",
|
|
106
|
+
"dp.w": "mmw",
|
|
107
|
+
"x": "mmx",
|
|
108
|
+
"dp.x": "mmx",
|
|
109
|
+
},
|
|
110
|
+
"Linux": {
|
|
111
|
+
"v": "mlv",
|
|
112
|
+
"dp.v": "mlv",
|
|
113
|
+
"w": "mlw",
|
|
114
|
+
"dp.w": "mlw",
|
|
115
|
+
"x": "mlx",
|
|
116
|
+
"dp.x": "mlx",
|
|
117
|
+
},
|
|
118
|
+
"Windows": {
|
|
119
|
+
"v": "mwv",
|
|
120
|
+
"dp.v": "mwv",
|
|
121
|
+
"w": "mww",
|
|
122
|
+
"dp.w": "mww",
|
|
123
|
+
"x": "mwx",
|
|
124
|
+
"dp.x": "mwx",
|
|
125
|
+
},
|
|
126
|
+
"Unknown": {
|
|
127
|
+
"v": "mlv",
|
|
128
|
+
"dp.v": "mlv",
|
|
129
|
+
"w": "mlw",
|
|
130
|
+
"dp.w": "mlw",
|
|
131
|
+
"x": "mlx",
|
|
132
|
+
"dp.x": "mlx",
|
|
133
|
+
},
|
|
134
|
+
}
|
|
101
135
|
assert opts["yy"] == "yyenviron", opts["yy"]
|
|
102
136
|
assert opts["aa"] == 1, f"{opts['aa']} {os}"
|
|
103
137
|
assert opts["bb"] == 2, f"{opts['bb']} {os}"
|
|
@@ -145,12 +179,12 @@ def test_basic():
|
|
|
145
179
|
assert opts["dp.t"] == "2ammt", f"{opts['dp.t']} {os}"
|
|
146
180
|
assert opts["u"] == "2smmu", f"{opts['u']} {os}"
|
|
147
181
|
assert opts["dp.u"] == "2smmu", f"{opts['dp.u']} {os}"
|
|
148
|
-
assert opts["v"] == "
|
|
149
|
-
assert opts["dp.v"] == "
|
|
150
|
-
assert opts["w"] == "
|
|
151
|
-
assert opts["dp.w"] == "
|
|
152
|
-
assert opts["x"] == "
|
|
153
|
-
assert opts["dp.x"] == "
|
|
182
|
+
assert opts["v"] == local_overrides[os]["v"], f"{opts['v']} {os}"
|
|
183
|
+
assert opts["dp.v"] == local_overrides[os]["dp.v"], f"{opts['dp.v']} {os}"
|
|
184
|
+
assert opts["w"] == local_overrides[os]["w"], f"{opts['w']} {os}"
|
|
185
|
+
assert opts["dp.w"] == local_overrides[os]["dp.w"], f"{opts['dp.w']} {os}"
|
|
186
|
+
assert opts["x"] == local_overrides[os]["x"], f"{opts['x']} {os}"
|
|
187
|
+
assert opts["dp.x"] == local_overrides[os]["dp.x"], f"{opts['dp.x']} {os}"
|
|
154
188
|
assert opts["y"] == f"m{ltr[os]}y", f"{opts['y']} m{ltr[os]}y {os}"
|
|
155
189
|
assert opts["dp.y"] == f"m{ltr[os]}y", f"{opts['dp.y']} m{ltr[os]}y {os}"
|
|
156
190
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
""" init workitem module """
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|