pullup 0.0.8__tar.gz → 0.0.10__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.
- {pullup-0.0.8 → pullup-0.0.10}/PKG-INFO +4 -4
- {pullup-0.0.8 → pullup-0.0.10}/pullup/__init__.py +1 -1
- {pullup-0.0.8 → pullup-0.0.10}/pullup/_modidx.py +1 -1
- {pullup-0.0.8 → pullup-0.0.10}/pullup/deploy.py +2 -2
- {pullup-0.0.8 → pullup-0.0.10}/pullup/env.py +2 -2
- {pullup-0.0.8 → pullup-0.0.10}/pullup/workflows.py +19 -16
- {pullup-0.0.8 → pullup-0.0.10}/pyproject.toml +2 -2
- {pullup-0.0.8 → pullup-0.0.10}/.gitignore +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/LICENSE +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/README.md +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/drive.py +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/infra.py +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/pipeline.py +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/project.py +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/stack.py +0 -0
- {pullup-0.0.8 → pullup-0.0.10}/pullup/wfbuild.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pullup
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.10
|
|
4
4
|
Summary: build, release, and deploy projects
|
|
5
5
|
Project-URL: Repository, https://github.com/vedicreader/pullup
|
|
6
6
|
Project-URL: Documentation, https://vedicreader.github.io/pullup
|
|
@@ -14,15 +14,15 @@ Classifier: Natural Language :: English
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
16
|
Requires-Python: >=3.11
|
|
17
|
-
Requires-Dist: cfeasy>=0.0.
|
|
18
|
-
Requires-Dist: dockeasy>=0.0.
|
|
17
|
+
Requires-Dist: cfeasy>=0.0.8
|
|
18
|
+
Requires-Dist: dockeasy>=0.0.11
|
|
19
19
|
Requires-Dist: fastcore>=1.8.17
|
|
20
20
|
Requires-Dist: gheasy>=0.0.10
|
|
21
21
|
Requires-Dist: keyring>=25.0.0
|
|
22
22
|
Requires-Dist: ptymini>=0.0.5
|
|
23
23
|
Requires-Dist: python-dotenv>=1.0.0
|
|
24
24
|
Requires-Dist: pyyaml>=6.0
|
|
25
|
-
Requires-Dist: vpseasy>=0.0.
|
|
25
|
+
Requires-Dist: vpseasy>=0.0.26
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
|
|
28
28
|
# pullup
|
|
@@ -179,7 +179,6 @@ d = { 'settings': { 'branch': 'main',
|
|
|
179
179
|
'pullup.workflows._fastship': ('workflows.html#_fastship', 'pullup/workflows.py'),
|
|
180
180
|
'pullup.workflows._from_line': ('workflows.html#_from_line', 'pullup/workflows.py'),
|
|
181
181
|
'pullup.workflows._gh_authed': ('workflows.html#_gh_authed', 'pullup/workflows.py'),
|
|
182
|
-
'pullup.workflows._gheasy': ('workflows.html#_gheasy', 'pullup/workflows.py'),
|
|
183
182
|
'pullup.workflows._opened': ('workflows.html#_opened', 'pullup/workflows.py'),
|
|
184
183
|
'pullup.workflows._read': ('workflows.html#_read', 'pullup/workflows.py'),
|
|
185
184
|
'pullup.workflows._run_row': ('workflows.html#_run_row', 'pullup/workflows.py'),
|
|
@@ -187,4 +186,5 @@ d = { 'settings': { 'branch': 'main',
|
|
|
187
186
|
'pullup.workflows._wf_file': ('workflows.html#_wf_file', 'pullup/workflows.py'),
|
|
188
187
|
'pullup.workflows._wf_name': ('workflows.html#_wf_name', 'pullup/workflows.py'),
|
|
189
188
|
'pullup.workflows._yaml': ('workflows.html#_yaml', 'pullup/workflows.py'),
|
|
189
|
+
'pullup.workflows.gheasy_core': ('workflows.html#gheasy_core', 'pullup/workflows.py'),
|
|
190
190
|
'pullup.workflows.levels': ('workflows.html#levels', 'pullup/workflows.py')}}}
|
|
@@ -181,7 +181,7 @@ runs whatever this file says.
|
|
|
181
181
|
python deploy.py compose
|
|
182
182
|
python deploy.py deploy
|
|
183
183
|
python deploy.py status
|
|
184
|
-
python deploy.py rollback [tag]
|
|
184
|
+
python deploy.py rollback [tag|prev]
|
|
185
185
|
python deploy.py nuke [--tunnel]
|
|
186
186
|
"""
|
|
187
187
|
import os, sys, secrets
|
|
@@ -281,7 +281,7 @@ def after_deploy(cf):
|
|
|
281
281
|
except Exception as e: print(f'cache not purged: {{e}}')
|
|
282
282
|
|
|
283
283
|
def rollback(to=None):
|
|
284
|
-
"Run the image before the
|
|
284
|
+
"Run the kept image built before the running one, or the one tagged `to`; `prev` undoes the last deploy or rollback."
|
|
285
285
|
ip = env_get('HETZNER_IP', path=root/'.env')
|
|
286
286
|
if not ip: return print('no server yet')
|
|
287
287
|
vps_rollback(ip, to, path=srv, user=env_get('SERVER_USER', path=root/'.env', default='deploy'),
|
|
@@ -99,7 +99,7 @@ class EnvStore:
|
|
|
99
99
|
return {'key': key, 'secret': bool(secret)}
|
|
100
100
|
def unset(self, key):
|
|
101
101
|
"Remove a value from the keychain, the env file and `os.environ`, and say which of the first two held it."
|
|
102
|
-
from dockeasy.core import
|
|
102
|
+
from dockeasy.core import FASTOPS_ENV
|
|
103
103
|
from dotenv import unset_key
|
|
104
104
|
key, gone = str(key), []
|
|
105
105
|
try:
|
|
@@ -108,7 +108,7 @@ class EnvStore:
|
|
|
108
108
|
keyring.delete_password(self.service, key)
|
|
109
109
|
gone.append('keychain')
|
|
110
110
|
except Exception: pass
|
|
111
|
-
path = str(self.path or
|
|
111
|
+
path = str(self.path or FASTOPS_ENV)
|
|
112
112
|
try:
|
|
113
113
|
removed, _ = unset_key(path, key)
|
|
114
114
|
if removed: gone.append('env file')
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
# %% auto #0
|
|
7
|
-
__all__ = ['WORKFLOW_DIR', 'WorkflowError', 'levels', 'Workflows']
|
|
7
|
+
__all__ = ['WORKFLOW_DIR', 'WorkflowError', 'gheasy_core', 'levels', 'Workflows']
|
|
8
8
|
|
|
9
9
|
# %% ../nbs/05_workflows.ipynb #13d36d32
|
|
10
10
|
import re
|
|
@@ -29,13 +29,16 @@ class WorkflowError(RuntimeError):
|
|
|
29
29
|
pass
|
|
30
30
|
|
|
31
31
|
# %% ../nbs/05_workflows.ipynb #21f04074
|
|
32
|
-
def
|
|
32
|
+
def gheasy_core():
|
|
33
|
+
'Return the `gheasy.core` module, raising `WorkflowError` with the install hint when gheasy is missing.'
|
|
33
34
|
try:
|
|
34
35
|
import gheasy.core as core
|
|
35
36
|
return core
|
|
36
37
|
except ImportError as e:
|
|
37
38
|
raise WorkflowError(needs_extra('this needs gheasy')) from e
|
|
38
39
|
|
|
40
|
+
_gheasy = gheasy_core
|
|
41
|
+
|
|
39
42
|
def _opened(core, name, was=None):
|
|
40
43
|
"gheasy's helper under whichever spelling it has: public from 0.0.10, underscored before it."
|
|
41
44
|
for n in (name, was or f'_{name}'):
|
|
@@ -46,8 +49,8 @@ def _opened(core, name, was=None):
|
|
|
46
49
|
def _yaml():
|
|
47
50
|
"gheasy's ruamel instance for reading a workflow, or plain pyyaml where gheasy is not installed."
|
|
48
51
|
try:
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
from gheasy.workflow import yaml_instance
|
|
53
|
+
return yaml_instance()
|
|
51
54
|
except ImportError: pass
|
|
52
55
|
import yaml
|
|
53
56
|
class _Plain:
|
|
@@ -146,12 +149,12 @@ class Workflows:
|
|
|
146
149
|
def repo(self):
|
|
147
150
|
"`owner/name` from the origin remote, or `''` when there is no GitHub remote."
|
|
148
151
|
try:
|
|
149
|
-
core =
|
|
152
|
+
core = gheasy_core()
|
|
150
153
|
owner, name = _opened(core, 'repo_slug', '_get_repo_slug')(str(self.root))
|
|
151
154
|
return f'{owner}/{name}'
|
|
152
155
|
except Exception: return ''
|
|
153
156
|
def _api(self):
|
|
154
|
-
core =
|
|
157
|
+
core = gheasy_core()
|
|
155
158
|
token = _opened(core, 'gh_token', '_resolve_gh_token')()
|
|
156
159
|
if not token:
|
|
157
160
|
raise WorkflowError('set GITHUB_TOKEN — add it in Environment below, or export it before starting Leela')
|
|
@@ -161,7 +164,7 @@ class Workflows:
|
|
|
161
164
|
"Whether the GitHub features can be used, and if not, whether gheasy, a remote or a token is missing."
|
|
162
165
|
row = {'gheasy': True, 'dockeasy': installed('dockeasy'), 'repo': '', 'token': False,
|
|
163
166
|
'gh_cli': bool(which('gh')), 'gh_auth': _gh_authed(), 'why': ''}
|
|
164
|
-
try: core =
|
|
167
|
+
try: core = gheasy_core()
|
|
165
168
|
except WorkflowError as e: return row | {'gheasy': False, 'why': str(e)}
|
|
166
169
|
row['repo'] = self.repo()
|
|
167
170
|
row['token'] = bool(_opened(core, 'gh_token', '_resolve_gh_token')())
|
|
@@ -190,7 +193,7 @@ class Workflows:
|
|
|
190
193
|
"Start a run of a workflow that declares `workflow_dispatch`."
|
|
191
194
|
owner, name, api = self._api()
|
|
192
195
|
if not str(workflow).strip(): raise WorkflowError('choose a workflow to run')
|
|
193
|
-
ref = str(ref or '').strip() or
|
|
196
|
+
ref = str(ref or '').strip() or gheasy_core()._git_branch(str(self.root))
|
|
194
197
|
api.actions.create_workflow_dispatch(workflow_id=str(workflow), ref=ref, inputs=dict(inputs or {}))
|
|
195
198
|
return {'workflow': str(workflow), 'ref': ref}
|
|
196
199
|
def cancel(self, run_id):
|
|
@@ -200,19 +203,19 @@ class Workflows:
|
|
|
200
203
|
return {'cancelled': int(run_id)}
|
|
201
204
|
def config(self):
|
|
202
205
|
"The project's `.gheasy/config.json`, or None when gheasy has not been set up here."
|
|
203
|
-
try: core =
|
|
206
|
+
try: core = gheasy_core()
|
|
204
207
|
except WorkflowError: return None
|
|
205
208
|
if not core.cfg_path(str(self.root)).exists(): return None
|
|
206
209
|
return core.GheasyConfig.load(str(self.root)).to_dict()
|
|
207
210
|
def generate(self):
|
|
208
211
|
"The workflow gheasy would write for this project, as text, without writing it."
|
|
209
|
-
core =
|
|
212
|
+
core = gheasy_core()
|
|
210
213
|
if not core.cfg_path(str(self.root)).exists():
|
|
211
214
|
raise WorkflowError('this project has no .gheasy/config.json to generate from')
|
|
212
215
|
return core.mk_workflow(core.GheasyConfig.load(str(self.root)))
|
|
213
216
|
def write_generated(self):
|
|
214
217
|
"Write gheasy's generated workflow with `gh_workflow`, as the gheasy CLI does; nothing is committed."
|
|
215
|
-
core =
|
|
218
|
+
core = gheasy_core()
|
|
216
219
|
if not core.cfg_path(str(self.root)).exists():
|
|
217
220
|
raise WorkflowError('this project has no .gheasy/config.json to generate from')
|
|
218
221
|
core.gh_workflow(path=str(self.root))
|
|
@@ -307,13 +310,13 @@ class Workflows:
|
|
|
307
310
|
return wfb.build()
|
|
308
311
|
def build(self, spec):
|
|
309
312
|
"The YAML for a workflow-builder spec, composed with gheasy."
|
|
310
|
-
|
|
313
|
+
gheasy_core()
|
|
311
314
|
from .wfbuild import compose
|
|
312
315
|
cfg = self.config() or {}
|
|
313
316
|
return compose(spec, schema=self.schema(), app=str(cfg.get('app') or self.root.name))
|
|
314
317
|
def write_spec(self, spec, file=''):
|
|
315
318
|
"Write the YAML for a spec into `.github/workflows` and save the spec beside it."
|
|
316
|
-
|
|
319
|
+
gheasy_core()
|
|
317
320
|
from .wfbuild import save_spec
|
|
318
321
|
name = _wf_name(str(file or spec.get('file') or f"{spec.get('name') or 'ci'}.yml"))
|
|
319
322
|
text = self.build(spec)
|
|
@@ -334,11 +337,11 @@ class Workflows:
|
|
|
334
337
|
return {'spec': spec, 'stale': stale}
|
|
335
338
|
def preview(self, choice):
|
|
336
339
|
"The YAML a catalogue entry would write, without writing it."
|
|
337
|
-
|
|
340
|
+
gheasy_core()
|
|
338
341
|
return self._build(str(choice)).to_yaml()
|
|
339
342
|
def add(self, choice, file=''):
|
|
340
343
|
"Write one catalogue entry into `.github/workflows`; raises if the file exists."
|
|
341
|
-
|
|
344
|
+
gheasy_core()
|
|
342
345
|
rows = {r['id']: r for r in self.catalogue()['workflows']}
|
|
343
346
|
row = rows.get(str(choice))
|
|
344
347
|
if row is None: raise WorkflowError(f'unknown workflow: {choice}')
|
|
@@ -381,7 +384,7 @@ class Workflows:
|
|
|
381
384
|
return {'secrets': secrets, 'variables': variables}
|
|
382
385
|
def push_env(self, values, keys=(), dry_run=False):
|
|
383
386
|
"Push values for the declared keys to GitHub through gheasy, one result row per key."
|
|
384
|
-
core =
|
|
387
|
+
core = gheasy_core()
|
|
385
388
|
if not which('gh'):
|
|
386
389
|
raise WorkflowError('pushing secrets uses the GitHub CLI: install `gh` and run `gh auth login`')
|
|
387
390
|
schema = self.schema()
|
|
@@ -12,8 +12,8 @@ license = {text = "Apache-2.0"}
|
|
|
12
12
|
authors = [{name = "Karthik Rajgopal", email = "karthik.rajgopal@hotmail.com"}]
|
|
13
13
|
keywords = ['nbdev', 'jupyter', 'notebook', 'python']
|
|
14
14
|
classifiers = ["Natural Language :: English", "Intended Audience :: Developers", "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only"]
|
|
15
|
-
dependencies = ['fastcore>=1.8.17', 'ptymini>=0.0.5', 'pyyaml>=6.0', 'dockeasy>=0.0.
|
|
16
|
-
'gheasy>=0.0.10', 'vpseasy>=0.0.
|
|
15
|
+
dependencies = ['fastcore>=1.8.17', 'ptymini>=0.0.5', 'pyyaml>=6.0', 'dockeasy>=0.0.11',
|
|
16
|
+
'gheasy>=0.0.10', 'vpseasy>=0.0.26', 'cfeasy>=0.0.8', 'python-dotenv>=1.0.0',
|
|
17
17
|
'keyring>=25.0.0']
|
|
18
18
|
|
|
19
19
|
[project.urls]
|
|
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
|