devopsdriver 0.1.37__tar.gz → 0.1.40__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.
Files changed (34) hide show
  1. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/PKG-INFO +28 -9
  2. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/README.md +19 -7
  3. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/__init__.py +3 -2
  4. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/azdo/__init__.py +2 -1
  5. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/azdo/clients.py +3 -0
  6. devopsdriver-0.1.40/devopsdriver/azdo/timestamp.py +133 -0
  7. devopsdriver-0.1.40/devopsdriver/azdo/workitem/__init__.py +1 -0
  8. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/azdo/workitem/client.py +3 -1
  9. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/azdo/workitem/wiql.py +1 -0
  10. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/azdo/workitem/workitem.py +18 -3
  11. devopsdriver-0.1.40/devopsdriver/manage_settings.py +55 -0
  12. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/sendmail.py +4 -0
  13. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/settings.py +3 -36
  14. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver/template.py +2 -0
  15. devopsdriver-0.1.40/devopsdriver/templates/manage_settings.txt.mako +14 -0
  16. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver.egg-info/PKG-INFO +28 -9
  17. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver.egg-info/SOURCES.txt +6 -0
  18. devopsdriver-0.1.40/devopsdriver.egg-info/entry_points.txt +2 -0
  19. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver.egg-info/requires.txt +10 -0
  20. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/pyproject.toml +18 -1
  21. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_azure_clients.py +1 -1
  22. devopsdriver-0.1.40/tests/test_azure_timestamp.py +308 -0
  23. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_azure_workitem.py +18 -9
  24. devopsdriver-0.1.40/tests/test_manage_settings.py +80 -0
  25. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_sendmail.py +1 -1
  26. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_settings.py +1 -44
  27. devopsdriver-0.1.37/devopsdriver/azdo/workitem/__init__.py +0 -4
  28. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/LICENSE +0 -0
  29. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver.egg-info/dependency_links.txt +0 -0
  30. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/devopsdriver.egg-info/top_level.txt +0 -0
  31. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/setup.cfg +0 -0
  32. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_azure_workitem_client.py +0 -0
  33. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_azure_workitem_wiql.py +0 -0
  34. {devopsdriver-0.1.37 → devopsdriver-0.1.40}/tests/test_template.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: devopsdriver
3
- Version: 0.1.37
3
+ Version: 0.1.40
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.
@@ -32,7 +32,7 @@ Project-URL: Homepage, https://github.com/marcpage/devops-driver
32
32
  Project-URL: Documentation, https://github.com/marcpage/devops-driver
33
33
  Project-URL: Repository, https://github.com/marcpage/devops-driver.git
34
34
  Project-URL: Issues, https://github.com/marcpage/devops-driver/issues
35
- Project-URL: Changelog, https://github.com/marcpage/devops-driver
35
+ Project-URL: Changelog, https://github.com/marcpage/devops-driver/releases
36
36
  Keywords: azure,devops,jira,confluence,email,pipelines,tools
37
37
  Classifier: Development Status :: 1 - Planning
38
38
  Classifier: Environment :: Console
@@ -51,9 +51,16 @@ Requires-Dist: keyring==25.0.0
51
51
  Requires-Dist: setuptools==69.0.2
52
52
  Requires-Dist: azure-devops==7.1.0b4
53
53
  Requires-Dist: Mako==1.3.2
54
+ Provides-Extra: dev
55
+ Requires-Dist: black>=24.3.0; extra == "dev"
56
+ Requires-Dist: pylint>=3.1.0; extra == "dev"
57
+ Provides-Extra: test
58
+ Requires-Dist: pytest>=8.1.1; extra == "test"
59
+ Requires-Dist: coverage>=7.4.4; extra == "test"
60
+ Provides-Extra: doc
54
61
 
55
62
  ![status sheild](https://img.shields.io/static/v1?label=status&message=beta&color=blue&style=plastic)
56
- [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.37&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.37/)
63
+ [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.40&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.40/)
57
64
  [![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
58
65
  [![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)
59
66
  [![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
@@ -84,7 +91,16 @@ OS:
84
91
 
85
92
  Devops-driver is a collection of tools to help streamline developer's experience and gain insights into various processes.
86
93
 
87
- ## Access to secrets
94
+ ## Tools
95
+
96
+ devopsdriver is a toolbox that helps to quickly put together reports. Some of the items in the toolbox are:
97
+
98
+ - **Settings**: store data, constants, settings, keys, tokens, etc. both in and out of the repository
99
+ - **send_email**: send emails over SMTP (including SSL), using `Settings` to store credentials
100
+ - **Template**: Simplify generating reports using `.mako` templates
101
+ - **Azure.workitem**: Search for and inspect Azure DevOps work items
102
+
103
+ ## Example use-case
88
104
 
89
105
  To allow seamless work in both pipelines as well as in the development environment, the `Settings` object gives you access to common settings among multiple scripts, secrets, and configuration constants in a way the helps keep secrets out of the repository but runs just as well in the pipeline as your machine.
90
106
 
@@ -101,7 +117,6 @@ secrets:
101
117
  ```
102
118
 
103
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.
104
- The `secrets` are extra sensative and are stored in the OS keychain.
105
120
 
106
121
  | Platform | Global Directory |
107
122
  |----------|------------------------|
@@ -109,26 +124,28 @@ The `secrets` are extra sensative and are stored in the OS keychain.
109
124
  | Linux | ~/.devopsdriver/ |
110
125
  | macOS | ~/Library/Preferences/ |
111
126
 
127
+ The `secrets` are extra sensative and are stored in the OS keychain.
128
+
112
129
  ### Set secrets in the keychain
113
130
  ```bash
114
131
  $ python3 -m venv .venv
115
132
  $ source .venv/bin/activate
116
133
  $ pip install devopsdriver
117
- $ python -m devopsdriver.settings --secrets
134
+ $ settings --secrets
118
135
  secret: smtp.password key: smtp/password
119
136
  smtp.password (smtp/password): ****
120
137
  secret: azure.token key: azure/token
121
138
  smtp.password (azure/token): ****
122
- $ python -m devopsdriver.settings --secrets
139
+ $ settings --secrets
123
140
  secret: azure.token key: azure/token
124
141
  Value set
125
142
  secret: smtp.password key: smtp/password
126
143
  Value set
127
144
  $
128
145
  ```
129
- The first call to `devopsdriver.settings` will look for every secret and check if they are already set in the keychain.
146
+ The first call to `settings` will look for every secret and check if they are already set in the keychain.
130
147
  For any secret that has not been set in the keychain, you will be prompted to enter the password to store.
131
- The second call to `devopsdriver.settings` will verify that all the values have been set in the keychain.
148
+ The second call to `settings` will verify that all the values have been set in the keychain.
132
149
 
133
150
  ### devopsdriver.yml
134
151
  ```yaml
@@ -174,6 +191,8 @@ These are values that you want to use in your script but have them here for easy
174
191
  </ul>
175
192
  ```
176
193
 
194
+ This file is the template for the email body.
195
+
177
196
  ### new_stories.py
178
197
  ```python
179
198
  from datetime import date, timedelta
@@ -1,5 +1,5 @@
1
1
  ![status sheild](https://img.shields.io/static/v1?label=status&message=beta&color=blue&style=plastic)
2
- [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.37&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.37/)
2
+ [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.40&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.40/)
3
3
  [![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
4
4
  [![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)
5
5
  [![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
@@ -30,7 +30,16 @@ OS:
30
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
- ## Access to secrets
33
+ ## Tools
34
+
35
+ devopsdriver is a toolbox that helps to quickly put together reports. Some of the items in the toolbox are:
36
+
37
+ - **Settings**: store data, constants, settings, keys, tokens, etc. both in and out of the repository
38
+ - **send_email**: send emails over SMTP (including SSL), using `Settings` to store credentials
39
+ - **Template**: Simplify generating reports using `.mako` templates
40
+ - **Azure.workitem**: Search for and inspect Azure DevOps work items
41
+
42
+ ## Example use-case
34
43
 
35
44
  To allow seamless work in both pipelines as well as in the development environment, the `Settings` object gives you access to common settings among multiple scripts, secrets, and configuration constants in a way the helps keep secrets out of the repository but runs just as well in the pipeline as your machine.
36
45
 
@@ -47,7 +56,6 @@ secrets:
47
56
  ```
48
57
 
49
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.
50
- The `secrets` are extra sensative and are stored in the OS keychain.
51
59
 
52
60
  | Platform | Global Directory |
53
61
  |----------|------------------------|
@@ -55,26 +63,28 @@ The `secrets` are extra sensative and are stored in the OS keychain.
55
63
  | Linux | ~/.devopsdriver/ |
56
64
  | macOS | ~/Library/Preferences/ |
57
65
 
66
+ The `secrets` are extra sensative and are stored in the OS keychain.
67
+
58
68
  ### Set secrets in the keychain
59
69
  ```bash
60
70
  $ python3 -m venv .venv
61
71
  $ source .venv/bin/activate
62
72
  $ pip install devopsdriver
63
- $ python -m devopsdriver.settings --secrets
73
+ $ settings --secrets
64
74
  secret: smtp.password key: smtp/password
65
75
  smtp.password (smtp/password): ****
66
76
  secret: azure.token key: azure/token
67
77
  smtp.password (azure/token): ****
68
- $ python -m devopsdriver.settings --secrets
78
+ $ settings --secrets
69
79
  secret: azure.token key: azure/token
70
80
  Value set
71
81
  secret: smtp.password key: smtp/password
72
82
  Value set
73
83
  $
74
84
  ```
75
- The first call to `devopsdriver.settings` will look for every secret and check if they are already set in the keychain.
85
+ The first call to `settings` will look for every secret and check if they are already set in the keychain.
76
86
  For any secret that has not been set in the keychain, you will be prompted to enter the password to store.
77
- The second call to `devopsdriver.settings` will verify that all the values have been set in the keychain.
87
+ The second call to `settings` will verify that all the values have been set in the keychain.
78
88
 
79
89
  ### devopsdriver.yml
80
90
  ```yaml
@@ -120,6 +130,8 @@ These are values that you want to use in your script but have them here for easy
120
130
  </ul>
121
131
  ```
122
132
 
133
+ This file is the template for the email body.
134
+
123
135
  ### new_stories.py
124
136
  ```python
125
137
  from datetime import date, timedelta
@@ -1,10 +1,11 @@
1
1
  """ DevOps tools """
2
2
 
3
- from .azdo import Azure
4
3
  from .settings import Settings
5
4
  from .sendmail import send_email
6
5
  from .template import Template
6
+ from .azdo.clients import Azure
7
7
 
8
- __version__ = "0.1.37"
8
+
9
+ __version__ = "0.1.40"
9
10
  __author__ = "Marc Page"
10
11
  __credits__ = ""
@@ -2,8 +2,9 @@
2
2
 
3
3
  # re export symbols for easier use
4
4
  from .clients import Azure
5
+ from .timestamp import Timestamp
5
6
 
6
- from .workitem import WorkItem
7
+ from .workitem.workitem import WorkItem
7
8
  from .workitem.wiql import Wiql, Value, Field
8
9
  from .workitem.wiql import Ascending, Descending, And, Or
9
10
  from .workitem.wiql import Equal, NotEqual, LessThanOrEqual, GreaterThanOrEqual
@@ -7,12 +7,15 @@ API Documented here:
7
7
  https://github.com/microsoft/azure-devops-python-api
8
8
  """
9
9
 
10
+
10
11
  from azure.devops.connection import Connection as AzureConnection
11
12
  from msrest.authentication import BasicAuthentication as MSBasicAuthentication
12
13
 
13
14
  from devopsdriver.settings import Settings
14
15
  from devopsdriver.azdo.workitem.client import Client as WIClient
15
16
 
17
+
18
+ # for testing
16
19
  CONNECTION = AzureConnection
17
20
  AUTHENTICATION = MSBasicAuthentication
18
21
 
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ """ Tools that help when working with Azure """
5
+
6
+
7
+ from datetime import datetime, timezone, timedelta
8
+ from functools import total_ordering
9
+
10
+
11
+ @total_ordering
12
+ class Timestamp:
13
+ """An Azure timestamp"""
14
+
15
+ DATE_FORMAT = "%Y-%m-%dT%H:%M:%S"
16
+ US_PER_MS = 1000 # microseconds per millisecond
17
+ US_PER_SEC = 1000 * US_PER_MS # microseconds per second
18
+
19
+ @staticmethod
20
+ def is_timestamp(value: any) -> bool:
21
+ """Determines if the value is a timestamp string
22
+
23
+ Args:
24
+ value (any): The value to check
25
+
26
+ Returns:
27
+ bool: True if the value is an Azure timestamp
28
+ """
29
+ if not isinstance(value, str):
30
+ return False
31
+
32
+ if not value.endswith("Z"):
33
+ return False
34
+
35
+ try:
36
+ Timestamp.__parse_string(value)
37
+ return True
38
+
39
+ except ValueError:
40
+ return False
41
+
42
+ @staticmethod
43
+ def now():
44
+ """Returns a timestamp representing now"""
45
+ return Timestamp(datetime.now(tz=timezone.utc))
46
+
47
+ def __init__(self, value: datetime | str | float | int):
48
+ if isinstance(value, datetime):
49
+ self.value = value
50
+
51
+ elif isinstance(value, str):
52
+ self.value = Timestamp.__parse_string(value)
53
+
54
+ elif isinstance(value, (int, float)):
55
+ self.value = datetime.fromtimestamp(value, tz=timezone.utc)
56
+
57
+ def __str__(self) -> str:
58
+ return self.to_string()
59
+
60
+ def __lt__(self, other) -> bool:
61
+ match Timestamp.__comparison_type(other):
62
+ case 1:
63
+ return self.value < other.value
64
+ case 2:
65
+ return self.value < other
66
+ case _:
67
+ return NotImplemented
68
+
69
+ def __eq__(self, other) -> bool:
70
+ match Timestamp.__comparison_type(other):
71
+ case 1:
72
+ return self.value == other.value
73
+ case 2:
74
+ return self.value == other
75
+ case _:
76
+ return NotImplemented
77
+
78
+ def __sub__(self, other):
79
+ match Timestamp.__comparison_type(other):
80
+ case 1:
81
+ return self.value - other.value
82
+ case 2 | 3:
83
+ return self.value - other
84
+ case _:
85
+ return NotImplemented
86
+
87
+ def __add__(self, other):
88
+ if Timestamp.__comparison_type(other) != 3:
89
+ return NotImplemented
90
+
91
+ return Timestamp(self.value + other)
92
+
93
+ def to_string(self) -> str:
94
+ """Returns the Azure formatted timestamp
95
+
96
+ Returns:
97
+ str: The correctly formatted string
98
+ """
99
+ milliseconds = f"{self.value.microsecond / Timestamp.US_PER_MS:03.0f}".rstrip(
100
+ "0"
101
+ )
102
+ return f"{self.value.strftime(Timestamp.DATE_FORMAT)}.{milliseconds}Z"
103
+
104
+ def to_timestamp(self) -> float:
105
+ """Converts to a number to use with time.time()
106
+
107
+ Returns:
108
+ float: The number of seconds since the epoch
109
+ """
110
+ return datetime.timestamp(self.value)
111
+
112
+ @staticmethod
113
+ def __parse_string(timestamp: str) -> datetime:
114
+ assert timestamp.endswith("Z"), timestamp
115
+ whole, fractional = timestamp.rsplit(".", 1)
116
+ result = datetime.strptime(whole, Timestamp.DATE_FORMAT)
117
+ fractional_seconds = float(f"0.{fractional[:-1].ljust(3, '0')}")
118
+ return result.replace(
119
+ microsecond=int(fractional_seconds * Timestamp.US_PER_SEC)
120
+ ).replace(tzinfo=timezone.utc)
121
+
122
+ @staticmethod
123
+ def __comparison_type(other) -> int:
124
+ if isinstance(other, timedelta):
125
+ return 3
126
+
127
+ if isinstance(other, datetime):
128
+ return 2
129
+
130
+ if hasattr(other, "value") and isinstance(other.value, datetime):
131
+ return 1
132
+
133
+ return 0
@@ -0,0 +1 @@
1
+ """ init workitem module """
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+
3
4
  """ Azure WorkItem Client """
4
5
 
6
+
5
7
  from azure.devops.v7_1.work_item_tracking.models import Wiql as AzureWiql
6
8
  from azure.devops.v7_1.work_item_tracking.models import WorkItem as AzureWorkItem
7
9
  from azure.devops.v7_1.work_item_tracking.models import TeamContext
8
10
  from azure.devops.v7_1.work_item_tracking.models import WorkItemQueryResult
9
- from devopsdriver.azdo.workitem import WorkItem
11
+ from devopsdriver.azdo.workitem.workitem import WorkItem
10
12
  from devopsdriver.azdo.workitem.wiql import Wiql
11
13
 
12
14
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+
3
4
  """ Builds a WIQL query
4
5
  https://learn.microsoft.com/en-us/azure/devops/boards/queries/wiql-syntax?view=azure-devops
5
6
 
@@ -1,10 +1,15 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+
3
4
  """ An Azure Devops WorkItem """
4
5
 
6
+
5
7
  from typing import Any
8
+
6
9
  from azure.devops.v7_1.work_item_tracking.models import WorkItem as AzureWorkItem
7
10
 
11
+ from devopsdriver.azdo.timestamp import Timestamp
12
+
8
13
 
9
14
  class WorkItem: # pylint: disable=too-few-public-methods
10
15
  """Azure WorkItem"""
@@ -43,11 +48,21 @@ class WorkItem: # pylint: disable=too-few-public-methods
43
48
  if "fields" in data:
44
49
  return WorkItem._parse_field(name, data["fields"])
45
50
 
46
- raise AttributeError(f"'WorkItem' object has no attribute '{name}'")
51
+ return None
47
52
 
48
53
  class _Dict(dict):
49
54
  def __getattr__(self, name: str) -> Any:
50
- return WorkItem._parse_field(name, self)
55
+ value = WorkItem._parse_field(name, self)
56
+
57
+ if Timestamp.is_timestamp(value):
58
+ return Timestamp(value)
59
+
60
+ return value
51
61
 
52
62
  def __getattr__(self, name: str) -> Any:
53
- return WorkItem._parse_field(name, self.raw.as_dict())
63
+ value = WorkItem._parse_field(name, self.raw.as_dict())
64
+
65
+ if Timestamp.is_timestamp(value):
66
+ return Timestamp(value)
67
+
68
+ return value
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ """ Module Doc """
5
+
6
+
7
+ from os.path import dirname, join
8
+ from sys import argv as sys_argv
9
+ from getpass import getpass as os_getpass
10
+
11
+ from keyring import set_password
12
+
13
+ from .settings import Settings
14
+ from .template import Template
15
+
16
+ ARGV = sys_argv
17
+ PRINT = print
18
+ SET_PASSWORD = set_password
19
+ GET_PASS = os_getpass
20
+
21
+
22
+ def main() -> None:
23
+ """Get settings values"""
24
+ args = list(ARGV[1:])
25
+
26
+ if not args or "--help" in args or "-h" in args:
27
+ PRINT(
28
+ Template(
29
+ __file__, join(dirname(__file__), "templates"), extension=".txt.mako"
30
+ ).render()
31
+ )
32
+ return
33
+
34
+ settings = Settings(__file__, dirname(dirname(__file__))).key("secrets")
35
+
36
+ if "--secrets" in args:
37
+ args.remove("--secrets")
38
+
39
+ for secret, key in settings.secrets.items():
40
+ PRINT(f"secret: {secret} key: {key}")
41
+
42
+ if not settings.has(secret):
43
+ value = GET_PASS(f"{secret} ({key}): ")
44
+
45
+ if value:
46
+ SET_PASSWORD(*Settings.split_key(key), value)
47
+ else:
48
+ PRINT("\tValue set")
49
+
50
+ for arg in args:
51
+ PRINT(f"{settings.get(arg)}")
52
+
53
+
54
+ if __name__ == "__main__":
55
+ main()
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+
3
4
  """ Ability to send emails with embedded images """
5
+
6
+
4
7
  from smtplib import SMTP as OS_SMTP, SMTP_SSL as OS_SMTP_SSL
5
8
  from email.mime.multipart import MIMEMultipart as OS_MIMEMultipart
6
9
  from email.mime.text import MIMEText as OS_MIMEText
@@ -8,6 +11,7 @@ from email.mime.image import MIMEImage as OS_MIMEImage
8
11
 
9
12
  from devopsdriver.settings import Settings
10
13
 
14
+
11
15
  IMAGE_HEADERS = {".png": b"\x89PNG\r\n\x1a\n", ".jpg": b"\xff\xd8\xff"}
12
16
 
13
17
  # for testing
@@ -86,6 +86,8 @@ from getpass import getpass as os_getpass
86
86
 
87
87
  from yaml import safe_load
88
88
  from keyring import get_password, set_password
89
+ from keyring.backends import fail
90
+
89
91
 
90
92
  # for testing
91
93
  ENVIRON = os_environ
@@ -266,7 +268,7 @@ class Settings:
266
268
  if key in self.secrets:
267
269
  value = GET_PASSWORD(*Settings.split_key(self.secrets[key]))
268
270
 
269
- if value is not None:
271
+ if value is not None and not isinstance(value, fail.Keyring):
270
272
  return True if check else value
271
273
 
272
274
  # Last check the files for settings
@@ -357,38 +359,3 @@ class Settings:
357
359
  Settings.__merge(settings, contents)
358
360
 
359
361
  return settings
360
-
361
-
362
- def main() -> None:
363
- """Get settings values"""
364
- args = list(ARGV[1:])
365
-
366
- if not args or "--help" in args or "-h" in args:
367
- PRINT("pass in settings to see if they are set and to what value")
368
- PRINT("You can pass dotted names to get inner values, like smpt.server")
369
- PRINT("You can pass --secrets to set keychain values that have not been set")
370
- PRINT("You can also pass --help or -h to get this message")
371
- return
372
-
373
- settings = Settings(__file__, dirname(dirname(__file__))).key("secrets")
374
-
375
- if "--secrets" in args:
376
- args.remove("--secrets")
377
-
378
- for secret, key in settings.secrets.items():
379
- PRINT(f"secret: {secret} key: {key}")
380
-
381
- if not settings.has(secret):
382
- value = GET_PASS(f"{secret} ({key}): ")
383
-
384
- if value:
385
- SET_PASSWORD(*Settings.split_key(key), value)
386
- else:
387
- PRINT("\tValue set")
388
-
389
- for arg in args:
390
- PRINT(f"{settings.get(arg)}")
391
-
392
-
393
- if __name__ == "__main__":
394
- main()
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+
3
4
  """ Module Doc """
4
5
 
6
+
5
7
  from os.path import dirname, basename, splitext
6
8
 
7
9
  from mako.lookup import TemplateLookup
@@ -0,0 +1,14 @@
1
+ Usage:
2
+
3
+ settings [-h | --help]
4
+ settings --secrets
5
+ settings <value>...
6
+
7
+ -h --help Display this help information
8
+
9
+ --secrets Prompt for any secrets that have not been set in the keychain
10
+ For secrets that are set, confirms that the value is set
11
+
12
+ <value> A value to display the value for. For instance:
13
+ "smtp" will display all the smtp values (but not secrets in smtp, like password)
14
+ "smtp.server" will display just the smtp server