drown 0.1.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.
- drown-0.1.0/LICENSE +21 -0
- drown-0.1.0/MANIFEST.in +3 -0
- drown-0.1.0/PKG-INFO +201 -0
- drown-0.1.0/README.md +159 -0
- drown-0.1.0/drown/__init__.py +3 -0
- drown-0.1.0/drown/api.py +130 -0
- drown-0.1.0/drown/cli.py +248 -0
- drown-0.1.0/drown/config.py +73 -0
- drown-0.1.0/drown.egg-info/PKG-INFO +201 -0
- drown-0.1.0/drown.egg-info/SOURCES.txt +15 -0
- drown-0.1.0/drown.egg-info/dependency_links.txt +1 -0
- drown-0.1.0/drown.egg-info/entry_points.txt +2 -0
- drown-0.1.0/drown.egg-info/requires.txt +2 -0
- drown-0.1.0/drown.egg-info/top_level.txt +1 -0
- drown-0.1.0/requirements.txt +2 -0
- drown-0.1.0/setup.cfg +4 -0
- drown-0.1.0/setup.py +47 -0
drown-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Drown Platform
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
drown-0.1.0/MANIFEST.in
ADDED
drown-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drown
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI tool for managing apps on Drown Platform - a self-hosted PaaS
|
|
5
|
+
Home-page: https://github.com/drownplatform/drown-cli
|
|
6
|
+
Author: Drown Platform
|
|
7
|
+
Author-email: platform@dr0wn.duckdns.org
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/drownplatform/drown-cli/issues
|
|
9
|
+
Project-URL: Documentation, https://github.com/drownplatform/drown-cli#readme
|
|
10
|
+
Project-URL: Source Code, https://github.com/drownplatform/drown-cli
|
|
11
|
+
Keywords: drown platform paas cli deployment docker heroku
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
24
|
+
Classifier: Topic :: System :: Systems Administration
|
|
25
|
+
Requires-Python: >=3.7
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: click>=8.0.0
|
|
29
|
+
Requires-Dist: requests>=2.25.0
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: project-url
|
|
39
|
+
Dynamic: requires-dist
|
|
40
|
+
Dynamic: requires-python
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# drown-cli
|
|
44
|
+
|
|
45
|
+
**CLI tool for managing apps on Drown Platform** - a self-hosted PaaS (Platform as a Service).
|
|
46
|
+
|
|
47
|
+
Deploy and manage containerized applications with simple commands, similar to Heroku CLI but for your own infrastructure.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install drown-cli
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Login to your Drown Platform instance
|
|
59
|
+
drown login
|
|
60
|
+
|
|
61
|
+
# List your apps
|
|
62
|
+
drown apps
|
|
63
|
+
|
|
64
|
+
# Create a new app
|
|
65
|
+
drown create my-app
|
|
66
|
+
|
|
67
|
+
# Scale your app
|
|
68
|
+
drown scale my-app 3
|
|
69
|
+
|
|
70
|
+
# View logs
|
|
71
|
+
drown logs my-app
|
|
72
|
+
|
|
73
|
+
# Check metrics
|
|
74
|
+
drown metrics my-app
|
|
75
|
+
|
|
76
|
+
# Logout
|
|
77
|
+
drown logout
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
### `drown login`
|
|
83
|
+
Authenticate with your Drown Platform instance. You'll be prompted for your username and password.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
drown login
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Credentials are saved to `~/.drown/config.json` for subsequent commands.
|
|
90
|
+
|
|
91
|
+
### `drown logout`
|
|
92
|
+
Remove saved credentials.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
drown logout
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `drown apps`
|
|
99
|
+
List all your deployed applications.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
drown apps
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Output:
|
|
106
|
+
```
|
|
107
|
+
NAME DOMAIN STATUS REPLICAS
|
|
108
|
+
my-app my-app.dr0wn.duckdns.org running 3
|
|
109
|
+
web-frontend web.dr0wn.duckdns.org running 1
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `drown create <app-name>`
|
|
113
|
+
Create a new application.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
drown create my-new-app
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If run from a git repository, automatically adds a `platform` git remote. Then deploy with:
|
|
120
|
+
```bash
|
|
121
|
+
git push platform main
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `drown scale <app-name> <count>`
|
|
125
|
+
Scale the number of replicas for an application.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
drown scale my-app 5
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `drown logs <app-name>`
|
|
132
|
+
View application logs.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
drown logs my-app
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `drown metrics <app-name>`
|
|
139
|
+
View resource usage metrics (CPU, memory) for all replicas.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
drown metrics my-app
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Output:
|
|
146
|
+
```
|
|
147
|
+
REPLICA PORT STATUS CPU MEMORY
|
|
148
|
+
0 8001 running 2.1% 64MiB
|
|
149
|
+
1 8002 running 1.8% 62MiB
|
|
150
|
+
2 8003 running 2.4% 65MiB
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
### API URL
|
|
156
|
+
By default, the CLI connects to `https://dashboard.dr0wn.duckdns.org`.
|
|
157
|
+
|
|
158
|
+
To use a custom instance, set the `DROWN_API_URL` environment variable:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
export DROWN_API_URL=https://your-instance.com
|
|
162
|
+
drown login
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Config File
|
|
166
|
+
Authentication token is stored in `~/.drown/config.json`:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"token": "your-jwt-token",
|
|
171
|
+
"username": "your-username",
|
|
172
|
+
"api_base": "https://dashboard.dr0wn.duckdns.org"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Requirements
|
|
177
|
+
|
|
178
|
+
- Python 3.7+
|
|
179
|
+
- Git (optional, for `drown create` auto-remote feature)
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/drownplatform/drown-cli.git
|
|
185
|
+
cd drown-cli
|
|
186
|
+
pip install -e .
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
192
|
+
|
|
193
|
+
## Links
|
|
194
|
+
|
|
195
|
+
- **Platform**: [dashboard.dr0wn.duckdns.org](https://dashboard.dr0wn.duckdns.org)
|
|
196
|
+
- **GitHub**: [github.com/drownplatform/drown-cli](https://github.com/drownplatform/drown-cli)
|
|
197
|
+
- **PyPI**: [pypi.org/project/drown-cli](https://pypi.org/project/drown-cli)
|
|
198
|
+
|
|
199
|
+
## Support
|
|
200
|
+
|
|
201
|
+
For issues or questions, please open an issue on [GitHub](https://github.com/drownplatform/drown-cli/issues).
|
drown-0.1.0/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# drown-cli
|
|
2
|
+
|
|
3
|
+
**CLI tool for managing apps on Drown Platform** - a self-hosted PaaS (Platform as a Service).
|
|
4
|
+
|
|
5
|
+
Deploy and manage containerized applications with simple commands, similar to Heroku CLI but for your own infrastructure.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install drown-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Login to your Drown Platform instance
|
|
17
|
+
drown login
|
|
18
|
+
|
|
19
|
+
# List your apps
|
|
20
|
+
drown apps
|
|
21
|
+
|
|
22
|
+
# Create a new app
|
|
23
|
+
drown create my-app
|
|
24
|
+
|
|
25
|
+
# Scale your app
|
|
26
|
+
drown scale my-app 3
|
|
27
|
+
|
|
28
|
+
# View logs
|
|
29
|
+
drown logs my-app
|
|
30
|
+
|
|
31
|
+
# Check metrics
|
|
32
|
+
drown metrics my-app
|
|
33
|
+
|
|
34
|
+
# Logout
|
|
35
|
+
drown logout
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
### `drown login`
|
|
41
|
+
Authenticate with your Drown Platform instance. You'll be prompted for your username and password.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
drown login
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Credentials are saved to `~/.drown/config.json` for subsequent commands.
|
|
48
|
+
|
|
49
|
+
### `drown logout`
|
|
50
|
+
Remove saved credentials.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
drown logout
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `drown apps`
|
|
57
|
+
List all your deployed applications.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
drown apps
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Output:
|
|
64
|
+
```
|
|
65
|
+
NAME DOMAIN STATUS REPLICAS
|
|
66
|
+
my-app my-app.dr0wn.duckdns.org running 3
|
|
67
|
+
web-frontend web.dr0wn.duckdns.org running 1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `drown create <app-name>`
|
|
71
|
+
Create a new application.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
drown create my-new-app
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If run from a git repository, automatically adds a `platform` git remote. Then deploy with:
|
|
78
|
+
```bash
|
|
79
|
+
git push platform main
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `drown scale <app-name> <count>`
|
|
83
|
+
Scale the number of replicas for an application.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
drown scale my-app 5
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `drown logs <app-name>`
|
|
90
|
+
View application logs.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
drown logs my-app
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### `drown metrics <app-name>`
|
|
97
|
+
View resource usage metrics (CPU, memory) for all replicas.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
drown metrics my-app
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Output:
|
|
104
|
+
```
|
|
105
|
+
REPLICA PORT STATUS CPU MEMORY
|
|
106
|
+
0 8001 running 2.1% 64MiB
|
|
107
|
+
1 8002 running 1.8% 62MiB
|
|
108
|
+
2 8003 running 2.4% 65MiB
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Configuration
|
|
112
|
+
|
|
113
|
+
### API URL
|
|
114
|
+
By default, the CLI connects to `https://dashboard.dr0wn.duckdns.org`.
|
|
115
|
+
|
|
116
|
+
To use a custom instance, set the `DROWN_API_URL` environment variable:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
export DROWN_API_URL=https://your-instance.com
|
|
120
|
+
drown login
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Config File
|
|
124
|
+
Authentication token is stored in `~/.drown/config.json`:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"token": "your-jwt-token",
|
|
129
|
+
"username": "your-username",
|
|
130
|
+
"api_base": "https://dashboard.dr0wn.duckdns.org"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Requirements
|
|
135
|
+
|
|
136
|
+
- Python 3.7+
|
|
137
|
+
- Git (optional, for `drown create` auto-remote feature)
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/drownplatform/drown-cli.git
|
|
143
|
+
cd drown-cli
|
|
144
|
+
pip install -e .
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
150
|
+
|
|
151
|
+
## Links
|
|
152
|
+
|
|
153
|
+
- **Platform**: [dashboard.dr0wn.duckdns.org](https://dashboard.dr0wn.duckdns.org)
|
|
154
|
+
- **GitHub**: [github.com/drownplatform/drown-cli](https://github.com/drownplatform/drown-cli)
|
|
155
|
+
- **PyPI**: [pypi.org/project/drown-cli](https://pypi.org/project/drown-cli)
|
|
156
|
+
|
|
157
|
+
## Support
|
|
158
|
+
|
|
159
|
+
For issues or questions, please open an issue on [GitHub](https://github.com/drownplatform/drown-cli/issues).
|
drown-0.1.0/drown/api.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""API wrapper functions for Drown Platform."""
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
from drown.config import get_api_base
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _make_request(method, endpoint, token=None, data=None):
|
|
8
|
+
"""
|
|
9
|
+
Make an HTTP request to the API.
|
|
10
|
+
|
|
11
|
+
Returns: (success: bool, result: dict)
|
|
12
|
+
"""
|
|
13
|
+
api_base = get_api_base()
|
|
14
|
+
url = f"{api_base}{endpoint}"
|
|
15
|
+
|
|
16
|
+
headers = {}
|
|
17
|
+
if token:
|
|
18
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
if method == "GET":
|
|
22
|
+
response = requests.get(url, headers=headers, timeout=10)
|
|
23
|
+
elif method == "POST":
|
|
24
|
+
headers["Content-Type"] = "application/json"
|
|
25
|
+
response = requests.post(url, headers=headers, json=data, timeout=10)
|
|
26
|
+
else:
|
|
27
|
+
return False, {"error": f"Unsupported HTTP method: {method}"}
|
|
28
|
+
|
|
29
|
+
# Handle different status codes
|
|
30
|
+
if response.status_code == 200:
|
|
31
|
+
try:
|
|
32
|
+
return True, response.json()
|
|
33
|
+
except ValueError:
|
|
34
|
+
return True, {"message": response.text}
|
|
35
|
+
elif response.status_code == 201:
|
|
36
|
+
try:
|
|
37
|
+
return True, response.json()
|
|
38
|
+
except ValueError:
|
|
39
|
+
return True, {"message": "Created successfully"}
|
|
40
|
+
elif response.status_code == 401:
|
|
41
|
+
return False, {"error": "Invalid credentials. Please run 'drown login' again."}
|
|
42
|
+
elif response.status_code == 403:
|
|
43
|
+
return False, {"error": "Forbidden: You don't have access to this resource."}
|
|
44
|
+
elif response.status_code == 404:
|
|
45
|
+
return False, {"error": "Not found. The app or resource doesn't exist."}
|
|
46
|
+
elif response.status_code == 400:
|
|
47
|
+
try:
|
|
48
|
+
error_data = response.json()
|
|
49
|
+
error_msg = error_data.get("error", "Bad request")
|
|
50
|
+
except ValueError:
|
|
51
|
+
error_msg = "Bad request"
|
|
52
|
+
return False, {"error": error_msg}
|
|
53
|
+
elif response.status_code >= 500:
|
|
54
|
+
return False, {"error": "Server error. Please try again later."}
|
|
55
|
+
else:
|
|
56
|
+
return False, {"error": f"Unexpected response: {response.status_code}"}
|
|
57
|
+
|
|
58
|
+
except requests.exceptions.ConnectionError:
|
|
59
|
+
return False, {"error": f"Unable to connect to {api_base}. Please check your internet connection."}
|
|
60
|
+
except requests.exceptions.Timeout:
|
|
61
|
+
return False, {"error": "Request timed out. Please try again."}
|
|
62
|
+
except requests.exceptions.RequestException as e:
|
|
63
|
+
return False, {"error": f"Network error: {str(e)}"}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def login(username, password):
|
|
67
|
+
"""
|
|
68
|
+
Authenticate with the platform.
|
|
69
|
+
|
|
70
|
+
Returns: (success: bool, result: dict)
|
|
71
|
+
result contains: {"token": "...", "username": "..."} or {"error": "..."}
|
|
72
|
+
"""
|
|
73
|
+
return _make_request("POST", "/api/auth/login", data={
|
|
74
|
+
"username": username,
|
|
75
|
+
"password": password
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_apps(token):
|
|
80
|
+
"""
|
|
81
|
+
Get list of all apps.
|
|
82
|
+
|
|
83
|
+
Returns: (success: bool, result: dict)
|
|
84
|
+
result contains: {"apps": [...]} or {"error": "..."}
|
|
85
|
+
"""
|
|
86
|
+
return _make_request("GET", "/api/apps", token=token)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def create_app(token, app_name):
|
|
90
|
+
"""
|
|
91
|
+
Create a new app.
|
|
92
|
+
|
|
93
|
+
Returns: (success: bool, result: dict)
|
|
94
|
+
result contains: {"app": {...}, "domain": "...", "git_remote": "...", "push_instructions": "..."} or {"error": "..."}
|
|
95
|
+
"""
|
|
96
|
+
return _make_request("POST", "/api/apps/create", token=token, data={
|
|
97
|
+
"name": app_name
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def scale_app(token, app_name, replicas):
|
|
102
|
+
"""
|
|
103
|
+
Scale an app to specified replica count.
|
|
104
|
+
|
|
105
|
+
Returns: (success: bool, result: dict)
|
|
106
|
+
result contains: {"app": {...}, "replicas": ...} or {"error": "..."}
|
|
107
|
+
"""
|
|
108
|
+
return _make_request("POST", f"/api/apps/{app_name}/scale", token=token, data={
|
|
109
|
+
"replicas": replicas
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_logs(token, app_name):
|
|
114
|
+
"""
|
|
115
|
+
Get logs for an app.
|
|
116
|
+
|
|
117
|
+
Returns: (success: bool, result: dict)
|
|
118
|
+
result contains: {"app": "...", "logs": "..."} or {"error": "..."}
|
|
119
|
+
"""
|
|
120
|
+
return _make_request("GET", f"/api/apps/{app_name}/logs", token=token)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def get_metrics(token, app_name):
|
|
124
|
+
"""
|
|
125
|
+
Get metrics for an app.
|
|
126
|
+
|
|
127
|
+
Returns: (success: bool, result: dict)
|
|
128
|
+
result contains: {"app": "...", "replicas": [...]} or {"error": "..."}
|
|
129
|
+
"""
|
|
130
|
+
return _make_request("GET", f"/api/apps/{app_name}/metrics", token=token)
|
drown-0.1.0/drown/cli.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""CLI commands for Drown Platform."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import getpass
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from drown import api, config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.group()
|
|
13
|
+
@click.version_option(version="0.1.0", prog_name="drown")
|
|
14
|
+
def cli():
|
|
15
|
+
"""Drown Platform CLI - Manage your self-hosted PaaS."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@cli.command()
|
|
20
|
+
def login():
|
|
21
|
+
"""Login to Drown Platform."""
|
|
22
|
+
click.echo("Login to Drown Platform")
|
|
23
|
+
click.echo(f"API: {config.get_api_base()}\n")
|
|
24
|
+
|
|
25
|
+
username = click.prompt("Username")
|
|
26
|
+
password = getpass.getpass("Password: ")
|
|
27
|
+
|
|
28
|
+
click.echo("\nAuthenticating...")
|
|
29
|
+
|
|
30
|
+
success, result = api.login(username, password)
|
|
31
|
+
|
|
32
|
+
if success:
|
|
33
|
+
token = result.get("token")
|
|
34
|
+
username = result.get("username")
|
|
35
|
+
|
|
36
|
+
config.save_config(token, username)
|
|
37
|
+
|
|
38
|
+
click.secho(f"✓ Logged in as {username}", fg="green")
|
|
39
|
+
click.echo(f"Config saved to {config.CONFIG_FILE}")
|
|
40
|
+
else:
|
|
41
|
+
click.secho(f"✗ Login failed: {result.get('error')}", fg="red", err=True)
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@cli.command()
|
|
46
|
+
def logout():
|
|
47
|
+
"""Logout and remove saved credentials."""
|
|
48
|
+
if config.delete_config():
|
|
49
|
+
click.secho("✓ Logged out successfully", fg="green")
|
|
50
|
+
click.echo(f"Removed {config.CONFIG_FILE}")
|
|
51
|
+
else:
|
|
52
|
+
click.echo("Not logged in")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@cli.command()
|
|
56
|
+
def apps():
|
|
57
|
+
"""List all your apps."""
|
|
58
|
+
token = config.get_token()
|
|
59
|
+
if not token:
|
|
60
|
+
click.secho("✗ Please run 'drown login' first", fg="red", err=True)
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
|
|
63
|
+
success, result = api.get_apps(token)
|
|
64
|
+
|
|
65
|
+
if not success:
|
|
66
|
+
click.secho(f"✗ Error: {result.get('error')}", fg="red", err=True)
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
|
|
69
|
+
apps_list = result.get("apps", [])
|
|
70
|
+
|
|
71
|
+
if not apps_list:
|
|
72
|
+
click.echo("No apps found. Create one with 'drown create <app-name>'")
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
# Print table header
|
|
76
|
+
click.echo(f"{'NAME':<20} {'DOMAIN':<35} {'STATUS':<10} {'REPLICAS':<8}")
|
|
77
|
+
click.echo("-" * 75)
|
|
78
|
+
|
|
79
|
+
# Print each app
|
|
80
|
+
for app in apps_list:
|
|
81
|
+
name = app.get("name", "")
|
|
82
|
+
domain = app.get("domain", "N/A")
|
|
83
|
+
status = app.get("status", "unknown")
|
|
84
|
+
replicas = app.get("replicas", 0)
|
|
85
|
+
|
|
86
|
+
# Color code status
|
|
87
|
+
if status == "running":
|
|
88
|
+
status_colored = click.style(status, fg="green")
|
|
89
|
+
elif status == "stopped":
|
|
90
|
+
status_colored = click.style(status, fg="red")
|
|
91
|
+
else:
|
|
92
|
+
status_colored = status
|
|
93
|
+
|
|
94
|
+
click.echo(f"{name:<20} {domain:<35} {status_colored:<10} {replicas:<8}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@cli.command()
|
|
98
|
+
@click.argument("app_name")
|
|
99
|
+
def create(app_name):
|
|
100
|
+
"""Create a new app."""
|
|
101
|
+
token = config.get_token()
|
|
102
|
+
if not token:
|
|
103
|
+
click.secho("✗ Please run 'drown login' first", fg="red", err=True)
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
|
|
106
|
+
click.echo(f"Creating app '{app_name}'...")
|
|
107
|
+
|
|
108
|
+
success, result = api.create_app(token, app_name)
|
|
109
|
+
|
|
110
|
+
if not success:
|
|
111
|
+
click.secho(f"✗ Error: {result.get('error')}", fg="red", err=True)
|
|
112
|
+
sys.exit(1)
|
|
113
|
+
|
|
114
|
+
domain = result.get("domain", "N/A")
|
|
115
|
+
git_remote = result.get("git_remote")
|
|
116
|
+
push_instructions = result.get("push_instructions", "")
|
|
117
|
+
|
|
118
|
+
click.secho(f"✓ App '{app_name}' created successfully!", fg="green")
|
|
119
|
+
click.echo(f"Domain: {domain}")
|
|
120
|
+
|
|
121
|
+
# Check if we're in a git repo
|
|
122
|
+
git_dir = Path(".git")
|
|
123
|
+
if git_dir.exists() and git_remote:
|
|
124
|
+
click.echo("\nAdding git remote 'platform'...")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
# Check if remote already exists
|
|
128
|
+
result = subprocess.run(
|
|
129
|
+
["git", "remote", "get-url", "platform"],
|
|
130
|
+
capture_output=True,
|
|
131
|
+
text=True
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if result.returncode == 0:
|
|
135
|
+
click.secho("⚠ Remote 'platform' already exists. Skipping.", fg="yellow")
|
|
136
|
+
else:
|
|
137
|
+
# Add the remote
|
|
138
|
+
subprocess.run(
|
|
139
|
+
["git", "remote", "add", "platform", git_remote],
|
|
140
|
+
check=True,
|
|
141
|
+
capture_output=True
|
|
142
|
+
)
|
|
143
|
+
click.secho(f"✓ Git remote 'platform' added", fg="green")
|
|
144
|
+
except subprocess.CalledProcessError as e:
|
|
145
|
+
click.secho(f"⚠ Failed to add git remote: {e}", fg="yellow")
|
|
146
|
+
except FileNotFoundError:
|
|
147
|
+
click.secho("⚠ Git not found. Please install git to use auto-remote feature.", fg="yellow")
|
|
148
|
+
|
|
149
|
+
# Print deployment instructions
|
|
150
|
+
if push_instructions:
|
|
151
|
+
click.echo(f"\n{push_instructions}")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@cli.command()
|
|
155
|
+
@click.argument("app_name")
|
|
156
|
+
@click.argument("count", type=int)
|
|
157
|
+
def scale(app_name, count):
|
|
158
|
+
"""Scale an app to COUNT replicas."""
|
|
159
|
+
token = config.get_token()
|
|
160
|
+
if not token:
|
|
161
|
+
click.secho("✗ Please run 'drown login' first", fg="red", err=True)
|
|
162
|
+
sys.exit(1)
|
|
163
|
+
|
|
164
|
+
if count < 0:
|
|
165
|
+
click.secho("✗ Replica count must be non-negative", fg="red", err=True)
|
|
166
|
+
sys.exit(1)
|
|
167
|
+
|
|
168
|
+
click.echo(f"Scaling '{app_name}' to {count} replica(s)...")
|
|
169
|
+
|
|
170
|
+
success, result = api.scale_app(token, app_name, count)
|
|
171
|
+
|
|
172
|
+
if not success:
|
|
173
|
+
click.secho(f"✗ Error: {result.get('error')}", fg="red", err=True)
|
|
174
|
+
sys.exit(1)
|
|
175
|
+
|
|
176
|
+
new_count = result.get("replicas", count)
|
|
177
|
+
click.secho(f"✓ Scaled '{app_name}' to {new_count} replica(s)", fg="green")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@cli.command()
|
|
181
|
+
@click.argument("app_name")
|
|
182
|
+
def logs(app_name):
|
|
183
|
+
"""View logs for an app."""
|
|
184
|
+
token = config.get_token()
|
|
185
|
+
if not token:
|
|
186
|
+
click.secho("✗ Please run 'drown login' first", fg="red", err=True)
|
|
187
|
+
sys.exit(1)
|
|
188
|
+
|
|
189
|
+
success, result = api.get_logs(token, app_name)
|
|
190
|
+
|
|
191
|
+
if not success:
|
|
192
|
+
click.secho(f"✗ Error: {result.get('error')}", fg="red", err=True)
|
|
193
|
+
sys.exit(1)
|
|
194
|
+
|
|
195
|
+
logs_text = result.get("logs", "")
|
|
196
|
+
|
|
197
|
+
if logs_text:
|
|
198
|
+
click.echo(logs_text)
|
|
199
|
+
else:
|
|
200
|
+
click.echo("No logs available")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@cli.command()
|
|
204
|
+
@click.argument("app_name")
|
|
205
|
+
def metrics(app_name):
|
|
206
|
+
"""View resource metrics for an app."""
|
|
207
|
+
token = config.get_token()
|
|
208
|
+
if not token:
|
|
209
|
+
click.secho("✗ Please run 'drown login' first", fg="red", err=True)
|
|
210
|
+
sys.exit(1)
|
|
211
|
+
|
|
212
|
+
success, result = api.get_metrics(token, app_name)
|
|
213
|
+
|
|
214
|
+
if not success:
|
|
215
|
+
click.secho(f"✗ Error: {result.get('error')}", fg="red", err=True)
|
|
216
|
+
sys.exit(1)
|
|
217
|
+
|
|
218
|
+
replicas = result.get("replicas", [])
|
|
219
|
+
|
|
220
|
+
if not replicas:
|
|
221
|
+
click.echo(f"No replicas found for '{app_name}'")
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
# Print table header
|
|
225
|
+
click.echo(f"{'REPLICA':<10} {'PORT':<8} {'STATUS':<10} {'CPU':<10} {'MEMORY':<15}")
|
|
226
|
+
click.echo("-" * 55)
|
|
227
|
+
|
|
228
|
+
# Print each replica
|
|
229
|
+
for replica in replicas:
|
|
230
|
+
replica_num = replica.get("replica_num", "?")
|
|
231
|
+
port = replica.get("port", "N/A")
|
|
232
|
+
status = replica.get("status", "unknown")
|
|
233
|
+
cpu = replica.get("cpu", "N/A")
|
|
234
|
+
memory = replica.get("memory", "N/A")
|
|
235
|
+
|
|
236
|
+
# Color code status
|
|
237
|
+
if status == "running":
|
|
238
|
+
status_colored = click.style(status, fg="green")
|
|
239
|
+
elif status == "stopped":
|
|
240
|
+
status_colored = click.style(status, fg="red")
|
|
241
|
+
else:
|
|
242
|
+
status_colored = status
|
|
243
|
+
|
|
244
|
+
click.echo(f"{replica_num:<10} {port:<8} {status_colored:<10} {cpu:<10} {memory:<15}")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
if __name__ == "__main__":
|
|
248
|
+
cli()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Configuration management for Drown CLI."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# Default API base URL
|
|
8
|
+
DEFAULT_API_BASE = "https://dashboard.dr0wn.duckdns.org"
|
|
9
|
+
|
|
10
|
+
# Config file location
|
|
11
|
+
CONFIG_DIR = Path.home() / ".drown"
|
|
12
|
+
CONFIG_FILE = CONFIG_DIR / "config.json"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_api_base():
|
|
16
|
+
"""Get API base URL from environment or default."""
|
|
17
|
+
return os.environ.get("DROWN_API_URL", DEFAULT_API_BASE)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def save_config(token, username):
|
|
21
|
+
"""Save authentication config to ~/.drown/config.json."""
|
|
22
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
23
|
+
|
|
24
|
+
config = {
|
|
25
|
+
"token": token,
|
|
26
|
+
"username": username,
|
|
27
|
+
"api_base": get_api_base()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
with open(CONFIG_FILE, "w") as f:
|
|
31
|
+
json.dump(config, f, indent=2)
|
|
32
|
+
|
|
33
|
+
# Set restrictive permissions (Unix-like systems)
|
|
34
|
+
if hasattr(os, 'chmod'):
|
|
35
|
+
os.chmod(CONFIG_FILE, 0o600)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def load_config():
|
|
39
|
+
"""Load authentication config from ~/.drown/config.json."""
|
|
40
|
+
if not CONFIG_FILE.exists():
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
with open(CONFIG_FILE, "r") as f:
|
|
45
|
+
config = json.load(f)
|
|
46
|
+
|
|
47
|
+
# Ensure api_base is set (for older config files)
|
|
48
|
+
if "api_base" not in config:
|
|
49
|
+
config["api_base"] = get_api_base()
|
|
50
|
+
|
|
51
|
+
return config
|
|
52
|
+
except (json.JSONDecodeError, IOError):
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def delete_config():
|
|
57
|
+
"""Delete the config file (logout)."""
|
|
58
|
+
if CONFIG_FILE.exists():
|
|
59
|
+
CONFIG_FILE.unlink()
|
|
60
|
+
return True
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_token():
|
|
65
|
+
"""Get the saved auth token, or None if not logged in."""
|
|
66
|
+
config = load_config()
|
|
67
|
+
return config["token"] if config else None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_username():
|
|
71
|
+
"""Get the saved username, or None if not logged in."""
|
|
72
|
+
config = load_config()
|
|
73
|
+
return config["username"] if config else None
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drown
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI tool for managing apps on Drown Platform - a self-hosted PaaS
|
|
5
|
+
Home-page: https://github.com/drownplatform/drown-cli
|
|
6
|
+
Author: Drown Platform
|
|
7
|
+
Author-email: platform@dr0wn.duckdns.org
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/drownplatform/drown-cli/issues
|
|
9
|
+
Project-URL: Documentation, https://github.com/drownplatform/drown-cli#readme
|
|
10
|
+
Project-URL: Source Code, https://github.com/drownplatform/drown-cli
|
|
11
|
+
Keywords: drown platform paas cli deployment docker heroku
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
24
|
+
Classifier: Topic :: System :: Systems Administration
|
|
25
|
+
Requires-Python: >=3.7
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: click>=8.0.0
|
|
29
|
+
Requires-Dist: requests>=2.25.0
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: project-url
|
|
39
|
+
Dynamic: requires-dist
|
|
40
|
+
Dynamic: requires-python
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# drown-cli
|
|
44
|
+
|
|
45
|
+
**CLI tool for managing apps on Drown Platform** - a self-hosted PaaS (Platform as a Service).
|
|
46
|
+
|
|
47
|
+
Deploy and manage containerized applications with simple commands, similar to Heroku CLI but for your own infrastructure.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install drown-cli
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Login to your Drown Platform instance
|
|
59
|
+
drown login
|
|
60
|
+
|
|
61
|
+
# List your apps
|
|
62
|
+
drown apps
|
|
63
|
+
|
|
64
|
+
# Create a new app
|
|
65
|
+
drown create my-app
|
|
66
|
+
|
|
67
|
+
# Scale your app
|
|
68
|
+
drown scale my-app 3
|
|
69
|
+
|
|
70
|
+
# View logs
|
|
71
|
+
drown logs my-app
|
|
72
|
+
|
|
73
|
+
# Check metrics
|
|
74
|
+
drown metrics my-app
|
|
75
|
+
|
|
76
|
+
# Logout
|
|
77
|
+
drown logout
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
### `drown login`
|
|
83
|
+
Authenticate with your Drown Platform instance. You'll be prompted for your username and password.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
drown login
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Credentials are saved to `~/.drown/config.json` for subsequent commands.
|
|
90
|
+
|
|
91
|
+
### `drown logout`
|
|
92
|
+
Remove saved credentials.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
drown logout
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `drown apps`
|
|
99
|
+
List all your deployed applications.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
drown apps
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Output:
|
|
106
|
+
```
|
|
107
|
+
NAME DOMAIN STATUS REPLICAS
|
|
108
|
+
my-app my-app.dr0wn.duckdns.org running 3
|
|
109
|
+
web-frontend web.dr0wn.duckdns.org running 1
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `drown create <app-name>`
|
|
113
|
+
Create a new application.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
drown create my-new-app
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If run from a git repository, automatically adds a `platform` git remote. Then deploy with:
|
|
120
|
+
```bash
|
|
121
|
+
git push platform main
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `drown scale <app-name> <count>`
|
|
125
|
+
Scale the number of replicas for an application.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
drown scale my-app 5
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `drown logs <app-name>`
|
|
132
|
+
View application logs.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
drown logs my-app
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `drown metrics <app-name>`
|
|
139
|
+
View resource usage metrics (CPU, memory) for all replicas.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
drown metrics my-app
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Output:
|
|
146
|
+
```
|
|
147
|
+
REPLICA PORT STATUS CPU MEMORY
|
|
148
|
+
0 8001 running 2.1% 64MiB
|
|
149
|
+
1 8002 running 1.8% 62MiB
|
|
150
|
+
2 8003 running 2.4% 65MiB
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
### API URL
|
|
156
|
+
By default, the CLI connects to `https://dashboard.dr0wn.duckdns.org`.
|
|
157
|
+
|
|
158
|
+
To use a custom instance, set the `DROWN_API_URL` environment variable:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
export DROWN_API_URL=https://your-instance.com
|
|
162
|
+
drown login
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Config File
|
|
166
|
+
Authentication token is stored in `~/.drown/config.json`:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"token": "your-jwt-token",
|
|
171
|
+
"username": "your-username",
|
|
172
|
+
"api_base": "https://dashboard.dr0wn.duckdns.org"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Requirements
|
|
177
|
+
|
|
178
|
+
- Python 3.7+
|
|
179
|
+
- Git (optional, for `drown create` auto-remote feature)
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/drownplatform/drown-cli.git
|
|
185
|
+
cd drown-cli
|
|
186
|
+
pip install -e .
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
192
|
+
|
|
193
|
+
## Links
|
|
194
|
+
|
|
195
|
+
- **Platform**: [dashboard.dr0wn.duckdns.org](https://dashboard.dr0wn.duckdns.org)
|
|
196
|
+
- **GitHub**: [github.com/drownplatform/drown-cli](https://github.com/drownplatform/drown-cli)
|
|
197
|
+
- **PyPI**: [pypi.org/project/drown-cli](https://pypi.org/project/drown-cli)
|
|
198
|
+
|
|
199
|
+
## Support
|
|
200
|
+
|
|
201
|
+
For issues or questions, please open an issue on [GitHub](https://github.com/drownplatform/drown-cli/issues).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
requirements.txt
|
|
5
|
+
setup.py
|
|
6
|
+
drown/__init__.py
|
|
7
|
+
drown/api.py
|
|
8
|
+
drown/cli.py
|
|
9
|
+
drown/config.py
|
|
10
|
+
drown.egg-info/PKG-INFO
|
|
11
|
+
drown.egg-info/SOURCES.txt
|
|
12
|
+
drown.egg-info/dependency_links.txt
|
|
13
|
+
drown.egg-info/entry_points.txt
|
|
14
|
+
drown.egg-info/requires.txt
|
|
15
|
+
drown.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
drown
|
drown-0.1.0/setup.cfg
ADDED
drown-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="drown",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
author="Drown Platform",
|
|
10
|
+
author_email="platform@dr0wn.duckdns.org",
|
|
11
|
+
description="CLI tool for managing apps on Drown Platform - a self-hosted PaaS",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/drownplatform/drown-cli",
|
|
15
|
+
project_urls={
|
|
16
|
+
"Bug Tracker": "https://github.com/drownplatform/drown-cli/issues",
|
|
17
|
+
"Documentation": "https://github.com/drownplatform/drown-cli#readme",
|
|
18
|
+
"Source Code": "https://github.com/drownplatform/drown-cli",
|
|
19
|
+
},
|
|
20
|
+
packages=find_packages(),
|
|
21
|
+
classifiers=[
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
|
+
"Environment :: Console",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"License :: OSI Approved :: MIT License",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.7",
|
|
29
|
+
"Programming Language :: Python :: 3.8",
|
|
30
|
+
"Programming Language :: Python :: 3.9",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Topic :: Software Development :: Build Tools",
|
|
34
|
+
"Topic :: System :: Systems Administration",
|
|
35
|
+
],
|
|
36
|
+
keywords="drown platform paas cli deployment docker heroku",
|
|
37
|
+
python_requires=">=3.7",
|
|
38
|
+
install_requires=[
|
|
39
|
+
"click>=8.0.0",
|
|
40
|
+
"requests>=2.25.0",
|
|
41
|
+
],
|
|
42
|
+
entry_points={
|
|
43
|
+
"console_scripts": [
|
|
44
|
+
"drown=drown.cli:cli",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
)
|