augint-tools 1.0.0__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.
- augint_tools-1.0.0/PKG-INFO +33 -0
- augint_tools-1.0.0/README.md +13 -0
- augint_tools-1.0.0/pyproject.toml +230 -0
- augint_tools-1.0.0/src/__init__.py +1 -0
- augint_tools-1.0.0/src/cost_explorer.py +28 -0
- augint_tools-1.0.0/src/resources/logging.json +40 -0
- augint_tools-1.0.0/src/secrets.py +88 -0
- augint_tools-1.0.0/src/util.py +16 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: augint-tools
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Standard tools for Augmenting Integrations
|
|
5
|
+
Home-page: https://github.com/svange/openbrain
|
|
6
|
+
License: AGPL-3.0-only
|
|
7
|
+
Author: Samuel Vange
|
|
8
|
+
Author-email: 7166607+svange@users.noreply.github.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: boto3 (>=1.28.51,<2.0.0)
|
|
16
|
+
Requires-Dist: pygithub (>=2.3.0,<3.0.0)
|
|
17
|
+
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# Augmenting Integrations Tools
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
[](https://www.gnu.org/licenses/agpl-3.0)[](https://github.com/astral-sh/ruff)
|
|
25
|
+
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
|
|
26
|
+
[](https://conventionalcommits.org)
|
|
27
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
28
|
+
[](https://github.com/features/actions "Go to GitHub Actions homepage")
|
|
29
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
30
|
+
|
|
31
|
+
# Secrets
|
|
32
|
+
Push secrets from .env to GH Actions.
|
|
33
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Augmenting Integrations Tools
|
|
2
|
+

|
|
3
|
+
|
|
4
|
+

|
|
5
|
+
[](https://www.gnu.org/licenses/agpl-3.0)[](https://github.com/astral-sh/ruff)
|
|
6
|
+
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
|
|
7
|
+
[](https://conventionalcommits.org)
|
|
8
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
9
|
+
[](https://github.com/features/actions "Go to GitHub Actions homepage")
|
|
10
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
11
|
+
|
|
12
|
+
# Secrets
|
|
13
|
+
Push secrets from .env to GH Actions.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "augint-tools"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Standard tools for Augmenting Integrations"
|
|
5
|
+
authors = ["Samuel Vange <7166607+svange@users.noreply.github.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "AGPL-3.0-only"
|
|
8
|
+
packages = [{ include = "src" }]
|
|
9
|
+
homepage = "https://github.com/svange/openbrain"
|
|
10
|
+
|
|
11
|
+
[tool.poetry.scripts]
|
|
12
|
+
ai-secrets = "src.secrets:cli"
|
|
13
|
+
|
|
14
|
+
[tool.poetry.plugins."commitizen.plugin"] # completely untested
|
|
15
|
+
cz_conventional_commits = "commitizen.cz.conventional_commits:ConventionalCommitsCz"
|
|
16
|
+
#cz_jira = "commitizen.cz.jira:JiraSmartCz"
|
|
17
|
+
cz_customize = "commitizen.cz.customize:CustomizeCommitsCz"
|
|
18
|
+
cargo = "commitizen.providers:CargoProvider"
|
|
19
|
+
commitizen = "commitizen.providers:CommitizenProvider"
|
|
20
|
+
composer = "commitizen.providers:ComposerProvider"
|
|
21
|
+
npm = "commitizen.providers:NpmProvider"
|
|
22
|
+
pep621 = "commitizen.providers:Pep621Provider"
|
|
23
|
+
poetry = "commitizen.providers:PoetryProvider"
|
|
24
|
+
scm = "commitizen.providers:ScmProvider"
|
|
25
|
+
|
|
26
|
+
[tool.semantic_release]
|
|
27
|
+
major_on_zero = false
|
|
28
|
+
commit_message = "chore(release): release {version}"
|
|
29
|
+
|
|
30
|
+
# End from video
|
|
31
|
+
[tool.semantic_release.branches.main]
|
|
32
|
+
match = "main"
|
|
33
|
+
#commit_message = "chore(release): release {version}"
|
|
34
|
+
prerelease = false
|
|
35
|
+
|
|
36
|
+
[tool.semantic_release.branches.dev]
|
|
37
|
+
match = "dev"
|
|
38
|
+
#commit_message = "chore(pre-release): release {version}"
|
|
39
|
+
prerelease_token = "dev"
|
|
40
|
+
prerelease = true
|
|
41
|
+
|
|
42
|
+
version_toml = [
|
|
43
|
+
"pyproject.toml:tool.poetry.version",
|
|
44
|
+
]
|
|
45
|
+
version_variable = [
|
|
46
|
+
"openbrain/__init__.py:__version__",
|
|
47
|
+
]
|
|
48
|
+
build_command = "pip install poetry && poetry build"
|
|
49
|
+
#logging_use_named_masks = true
|
|
50
|
+
#major_on_zero = true
|
|
51
|
+
tag_format = "v{version}"
|
|
52
|
+
#exclude_commit_patterns = [
|
|
53
|
+
# 'skip: ',
|
|
54
|
+
#]
|
|
55
|
+
|
|
56
|
+
[tool.semantic_release.publish]
|
|
57
|
+
dist_glob_patterns = ["dist/*"]
|
|
58
|
+
upload_to_vcs_release = true
|
|
59
|
+
type = "github"
|
|
60
|
+
|
|
61
|
+
[tool.semantic_release.remote.token]
|
|
62
|
+
env = "GITHUB_TOKEN"
|
|
63
|
+
fallback_env = "GH_TOKEN"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
[tool.commitizen]
|
|
68
|
+
name = "cz_conventional_commits"
|
|
69
|
+
tag_format = "v$version"
|
|
70
|
+
version_scheme = "SemVer"
|
|
71
|
+
version_provider = "poetry" #"scm"
|
|
72
|
+
update_changelog_on_bump = true
|
|
73
|
+
major_version_zero = true
|
|
74
|
+
#version = "3.9.1"
|
|
75
|
+
#version_files = [
|
|
76
|
+
# "pyproject.toml:version",
|
|
77
|
+
# "openbrain/__version__.py",
|
|
78
|
+
# ".pre-commit-config.yaml:rev:.+Openbrain",
|
|
79
|
+
#]
|
|
80
|
+
|
|
81
|
+
[tool.poetry.plugins."commitizen.scheme"]
|
|
82
|
+
pep440 = "commitizen.version_schemes:Pep440"
|
|
83
|
+
semver = "commitizen.version_schemes:SemVer"
|
|
84
|
+
|
|
85
|
+
[tool.poetry.dependencies]
|
|
86
|
+
python = "^3.10"
|
|
87
|
+
boto3 = "^1.28.51"
|
|
88
|
+
pygithub = "^2.3.0"
|
|
89
|
+
python-dotenv = "^1.0.1"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
[tool.poetry.group.dev.dependencies]
|
|
93
|
+
pytest = "^7.4.2"
|
|
94
|
+
faker = "^19.6.1"
|
|
95
|
+
retry = "^0.9.2"
|
|
96
|
+
flake8 = "^7.1.0"
|
|
97
|
+
black = "^23.9.1"
|
|
98
|
+
reorder-python-imports = "^3.10.0"
|
|
99
|
+
python-semantic-release = "^9.8.5"
|
|
100
|
+
ruff = "^0.0.291"
|
|
101
|
+
mypy = "^1.5.1"
|
|
102
|
+
commitizen = "^3.9.1"
|
|
103
|
+
isort = "^5.12.0"
|
|
104
|
+
pre-commit = "^3.4.0"
|
|
105
|
+
coverage = "^7.3.2"
|
|
106
|
+
pygithub = "^2.1.1"
|
|
107
|
+
|
|
108
|
+
[tool.coverage] # not tested
|
|
109
|
+
[tool.coverage.report]
|
|
110
|
+
show_missing = true
|
|
111
|
+
exclude_lines = [
|
|
112
|
+
# Have to re-enable the standard pragma
|
|
113
|
+
'pragma: no cover',
|
|
114
|
+
# Don't complain about missing debug-only code:
|
|
115
|
+
'def __repr__',
|
|
116
|
+
'if self\.debug',
|
|
117
|
+
# Don't complain if tests don't hit defensive assertion code:
|
|
118
|
+
'raise AssertionError',
|
|
119
|
+
'raise NotImplementedError',
|
|
120
|
+
# Don't complain if non-runnable code isn't run:
|
|
121
|
+
'if 0:',
|
|
122
|
+
'if __name__ == .__main__.:',
|
|
123
|
+
'if TYPE_CHECKING:',
|
|
124
|
+
]
|
|
125
|
+
omit = [
|
|
126
|
+
'env/*',
|
|
127
|
+
'venv/*',
|
|
128
|
+
'.venv/*',
|
|
129
|
+
'*/virtualenv/*',
|
|
130
|
+
'*/virtualenvs/*',
|
|
131
|
+
'*/tests/*',
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[tool.pytest.ini_options]
|
|
135
|
+
addopts = '-m "not remote_tests and not redundant"'
|
|
136
|
+
|
|
137
|
+
[tool.ruff]
|
|
138
|
+
line-length = 130
|
|
139
|
+
ignore = [
|
|
140
|
+
"E501",
|
|
141
|
+
"D1",
|
|
142
|
+
"D415"
|
|
143
|
+
]
|
|
144
|
+
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
|
145
|
+
select = ["E", "F"]
|
|
146
|
+
|
|
147
|
+
[tool.ruff.isort]
|
|
148
|
+
known-first-party = ["commitizen", "tests"]
|
|
149
|
+
|
|
150
|
+
[tool.ruff.pydocstyle]
|
|
151
|
+
convention = "google"
|
|
152
|
+
|
|
153
|
+
[tool.mypy]
|
|
154
|
+
files = "commitizen"
|
|
155
|
+
disallow_untyped_decorators = true
|
|
156
|
+
disallow_subclassing_any = true
|
|
157
|
+
warn_return_any = true
|
|
158
|
+
warn_redundant_casts = true
|
|
159
|
+
warn_unused_ignores = true
|
|
160
|
+
warn_unused_configs = true
|
|
161
|
+
|
|
162
|
+
[[tool.mypy.overrides]]
|
|
163
|
+
module = "py.*" # Legacy pytest dependencies
|
|
164
|
+
ignore_missing_imports = true
|
|
165
|
+
|
|
166
|
+
[tool.black]
|
|
167
|
+
line-length = 130
|
|
168
|
+
target-version = ['py310']
|
|
169
|
+
include = '\.pyi?$'
|
|
170
|
+
exclude = '''
|
|
171
|
+
/(
|
|
172
|
+
\.git
|
|
173
|
+
| \.hg
|
|
174
|
+
| \.mypy_cache
|
|
175
|
+
| \.tox
|
|
176
|
+
| \.venv
|
|
177
|
+
| _build
|
|
178
|
+
| buck-out
|
|
179
|
+
| build
|
|
180
|
+
)/
|
|
181
|
+
'''
|
|
182
|
+
|
|
183
|
+
[tool.flake8]
|
|
184
|
+
max-line-length = 130
|
|
185
|
+
extend-ignore = ["D203", "E203", "E251", "E266", "E302", "E305", "E401", "E402", "E501", "F401", "F403", "W503"]
|
|
186
|
+
exclude = [".git", "__pycache__", "dist"]
|
|
187
|
+
max-complexity = 10
|
|
188
|
+
|
|
189
|
+
[tool.isort]
|
|
190
|
+
atomic = true
|
|
191
|
+
profile = "black"
|
|
192
|
+
line_length = 130
|
|
193
|
+
skip_gitignore = true
|
|
194
|
+
|
|
195
|
+
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
|
196
|
+
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
|
|
197
|
+
unfixable = []
|
|
198
|
+
|
|
199
|
+
# Exclude a variety of commonly ignored directories.
|
|
200
|
+
exclude = [
|
|
201
|
+
".bzr",
|
|
202
|
+
".direnv",
|
|
203
|
+
".eggs",
|
|
204
|
+
".git",
|
|
205
|
+
".git-rewrite",
|
|
206
|
+
".hg",
|
|
207
|
+
".mypy_cache",
|
|
208
|
+
".nox",
|
|
209
|
+
".pants.d",
|
|
210
|
+
".pytype",
|
|
211
|
+
".ruff_cache",
|
|
212
|
+
".svn",
|
|
213
|
+
".tox",
|
|
214
|
+
".venv",
|
|
215
|
+
"__pypackages__",
|
|
216
|
+
"_build",
|
|
217
|
+
"buck-out",
|
|
218
|
+
"build",
|
|
219
|
+
"dist",
|
|
220
|
+
"node_modules",
|
|
221
|
+
"venv",
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
# Same as Black.
|
|
225
|
+
line-length = 130
|
|
226
|
+
|
|
227
|
+
# Allow unused variables when underscore-prefixed.
|
|
228
|
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
229
|
+
|
|
230
|
+
target-version = "py310"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
|
|
5
|
+
os.environ["AWS_PROFILE"] = "personal"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def list_ec2_resources():
|
|
9
|
+
ec2 = boto3.resource("ec2")
|
|
10
|
+
|
|
11
|
+
print("Listing EC2 Instances:")
|
|
12
|
+
for instance in ec2.instances.all():
|
|
13
|
+
print(instance.id, instance.state, instance.instance_type)
|
|
14
|
+
|
|
15
|
+
print("\nListing EBS Snapshots:")
|
|
16
|
+
ec2_client = boto3.client("ec2")
|
|
17
|
+
snapshots = ec2_client.describe_snapshots(OwnerIds=["self"])
|
|
18
|
+
for snapshot in snapshots["Snapshots"]:
|
|
19
|
+
print(snapshot["SnapshotId"], snapshot["VolumeId"], snapshot["VolumeSize"])
|
|
20
|
+
|
|
21
|
+
print("\nListing Elastic IPs:")
|
|
22
|
+
elastic_ips = ec2_client.describe_addresses()
|
|
23
|
+
for eip in elastic_ips["Addresses"]:
|
|
24
|
+
print(eip["PublicIp"], eip.get("InstanceId", "Unassociated"))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
list_ec2_resources()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version":1,
|
|
3
|
+
"disable_existing_loggers":true,
|
|
4
|
+
"formatters":{
|
|
5
|
+
"standard":{
|
|
6
|
+
"format":"%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"handlers":{
|
|
10
|
+
"default":{
|
|
11
|
+
"level":"INFO",
|
|
12
|
+
"formatter":"standard",
|
|
13
|
+
"class":"logging.StreamHandler",
|
|
14
|
+
"stream":"ext://sys.stdout"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"loggers":{
|
|
18
|
+
"":{
|
|
19
|
+
"handlers":[
|
|
20
|
+
"default"
|
|
21
|
+
],
|
|
22
|
+
"level":"WARNING",
|
|
23
|
+
"propagate":false
|
|
24
|
+
},
|
|
25
|
+
"my.packg":{
|
|
26
|
+
"handlers":[
|
|
27
|
+
"default"
|
|
28
|
+
],
|
|
29
|
+
"level":"INFO",
|
|
30
|
+
"propagate":false
|
|
31
|
+
},
|
|
32
|
+
"__main__":{
|
|
33
|
+
"handlers":[
|
|
34
|
+
"default"
|
|
35
|
+
],
|
|
36
|
+
"level":"DEBUG",
|
|
37
|
+
"propagate":false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
from github import Github, Auth
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
from src.util import log
|
|
9
|
+
|
|
10
|
+
@click.command()
|
|
11
|
+
@click.option("--verbose", "-v", help="Verbose output.", is_flag=True)
|
|
12
|
+
@click.argument("filename", type=click.Path(exists=True, readable=True), default=".env")
|
|
13
|
+
def cli(verbose: bool, filename: click.Path):
|
|
14
|
+
if verbose:
|
|
15
|
+
log.info("Verbose output enabled.")
|
|
16
|
+
|
|
17
|
+
results = perform_update(filename)
|
|
18
|
+
log.info(results)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def perform_update(filename: click.Path):
|
|
22
|
+
if not filename:
|
|
23
|
+
raise ValueError("No filename specified. Exiting to avoid an accident.")
|
|
24
|
+
|
|
25
|
+
load_dotenv(str(filename))
|
|
26
|
+
github_repo = os.environ.get("GH_REPO", "ObInfra")
|
|
27
|
+
github_org = os.environ.get("GH_ORG", None)
|
|
28
|
+
github_user = os.environ.get("GH_USER", None)
|
|
29
|
+
|
|
30
|
+
file_path = Path(filename.__str__())
|
|
31
|
+
# Read the .env file and convert it to a JSON object
|
|
32
|
+
env_data = {}
|
|
33
|
+
with file_path.open("r") as file:
|
|
34
|
+
for line in file:
|
|
35
|
+
line = line.strip()
|
|
36
|
+
if not line or line.startswith("#") or line.startswith(";") or "=" not in line:
|
|
37
|
+
continue
|
|
38
|
+
key, value = line.strip().split("=", 1)
|
|
39
|
+
# Skip AWS Variables as they'll only confuse the pipeline
|
|
40
|
+
if key.startswith("AWS_PROFILE"):
|
|
41
|
+
continue
|
|
42
|
+
env_data[key] = os.getenv(key)
|
|
43
|
+
env_json = json.dumps(env_data)
|
|
44
|
+
|
|
45
|
+
results = []
|
|
46
|
+
result = create_or_update_github_secrets(
|
|
47
|
+
github_repo=github_repo, github_org=github_org, github_user=github_user, env_data=env_data
|
|
48
|
+
)
|
|
49
|
+
results.append(result)
|
|
50
|
+
|
|
51
|
+
return results
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_or_update_github_secrets(github_org, github_repo, github_user, env_data):
|
|
55
|
+
auth = Auth.Token(os.environ.get("GH_TOKEN", None))
|
|
56
|
+
g = Github(auth=auth)
|
|
57
|
+
if github_org:
|
|
58
|
+
g_org = g.get_organization(github_org)
|
|
59
|
+
repo = g_org.get_repo(github_repo)
|
|
60
|
+
elif github_user:
|
|
61
|
+
g_user = g.get_user(github_user)
|
|
62
|
+
repo = g_user.get_repo(github_repo)
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError("Must specify either GITHUB_ORG or GH_USER")
|
|
65
|
+
secrets = [secret for secret in repo.get_secrets()]
|
|
66
|
+
secret_names = [secret.name for secret in secrets]
|
|
67
|
+
|
|
68
|
+
results = []
|
|
69
|
+
for env_var_name, env_var_value in env_data.items():
|
|
70
|
+
# Create or update secrets
|
|
71
|
+
if env_var_name in secret_names:
|
|
72
|
+
log.info(f"Updating secret {env_var_name}...")
|
|
73
|
+
results.append(repo.create_secret(env_var_name, env_var_value))
|
|
74
|
+
|
|
75
|
+
else:
|
|
76
|
+
log.info(f"Creating secret {env_var_name}...")
|
|
77
|
+
results.append(repo.create_secret(env_var_name, env_var_value))
|
|
78
|
+
|
|
79
|
+
for secret_name in secret_names:
|
|
80
|
+
if secret_name not in env_data.keys():
|
|
81
|
+
log.info(f"Deleting secret {secret_name}...")
|
|
82
|
+
results.append(repo.delete_secret(secret_name))
|
|
83
|
+
|
|
84
|
+
return results
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
cli()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging.config
|
|
3
|
+
import os
|
|
4
|
+
import pathlib
|
|
5
|
+
|
|
6
|
+
this_dir = pathlib.Path(os.path.dirname(os.path.abspath(__file__)))
|
|
7
|
+
|
|
8
|
+
logging_config_path = this_dir / "resources/logging.json"
|
|
9
|
+
|
|
10
|
+
with open(logging_config_path, "r") as f:
|
|
11
|
+
LOGGING_CONFIG = json.load(f)
|
|
12
|
+
|
|
13
|
+
logging.config.dictConfig(LOGGING_CONFIG)
|
|
14
|
+
|
|
15
|
+
log = logging.getLogger(__name__)
|
|
16
|
+
log.debug("Logging is configured.")
|