c2cciutils 1.8.0.dev63__py3-none-any.whl → 1.8.0.dev68__py3-none-any.whl
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.
Potentially problematic release.
This version of c2cciutils might be problematic. Click here for more details.
- c2cciutils/__init__.py +1 -194
- c2cciutils/applications-versions.yaml +0 -1
- c2cciutils/configuration.py +1 -598
- c2cciutils/schema.json +2 -317
- {c2cciutils-1.8.0.dev63.dist-info → c2cciutils-1.8.0.dev68.dist-info}/METADATA +1 -219
- c2cciutils-1.8.0.dev68.dist-info/RECORD +25 -0
- c2cciutils-1.8.0.dev68.dist-info/entry_points.txt +9 -0
- c2cciutils/lib/docker.py +0 -141
- c2cciutils/lib/oidc.py +0 -188
- c2cciutils/package-lock.json +0 -370
- c2cciutils/package.json +0 -9
- c2cciutils/publish.py +0 -451
- c2cciutils/schema-applications.json +0 -50
- c2cciutils/scripts/clean.py +0 -103
- c2cciutils/scripts/docker_versions_gen.py +0 -33
- c2cciutils/scripts/pin_pipenv.py +0 -54
- c2cciutils/scripts/publish.py +0 -477
- c2cciutils/scripts/trigger_image_update.py +0 -84
- c2cciutils/scripts/version.py +0 -245
- c2cciutils-1.8.0.dev63.dist-info/RECORD +0 -37
- c2cciutils-1.8.0.dev63.dist-info/entry_points.txt +0 -18
- {c2cciutils-1.8.0.dev63.dist-info → c2cciutils-1.8.0.dev68.dist-info}/LICENSE +0 -0
- {c2cciutils-1.8.0.dev63.dist-info → c2cciutils-1.8.0.dev68.dist-info}/WHEEL +0 -0
c2cciutils/publish.py
DELETED
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
"""The publishing functions."""
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import datetime
|
|
5
|
-
import glob
|
|
6
|
-
import os
|
|
7
|
-
import pickle # nosec
|
|
8
|
-
import re
|
|
9
|
-
import subprocess # nosec
|
|
10
|
-
import sys
|
|
11
|
-
import uuid
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
|
-
import ruamel.yaml
|
|
15
|
-
import tomllib
|
|
16
|
-
from google.auth.transport.requests import Request
|
|
17
|
-
from google.oauth2.credentials import Credentials
|
|
18
|
-
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
19
|
-
from googleapiclient.discovery import build
|
|
20
|
-
|
|
21
|
-
import c2cciutils.configuration
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class GoogleCalendar:
|
|
25
|
-
"""Interact with the Google Calendar API."""
|
|
26
|
-
|
|
27
|
-
# pylint: disable=too-many-instance-attributes
|
|
28
|
-
def __init__(self) -> None:
|
|
29
|
-
"""Initialize."""
|
|
30
|
-
self.scopes = ["https://www.googleapis.com/auth/calendar"] # in fact it is better to hard-code this
|
|
31
|
-
self.credentials_pickle_file = os.environ.get("TMP_CREDS_FILE", f"/tmp/{uuid.uuid4()}.pickle") # noqa: S108 # nosec
|
|
32
|
-
self.credentials_json_file = os.environ.get(
|
|
33
|
-
"GOOGLE_CREDS_JSON_FILE", "~/google-credentials-c2cibot.json"
|
|
34
|
-
) # used to refresh the refresh_token or to initialize the credentials the first time
|
|
35
|
-
self.calendar_id = os.environ.get(
|
|
36
|
-
"GOOGLE_CALENDAR_ID", c2cciutils.gopass("gs/ci/google_calendar/calendarId")
|
|
37
|
-
)
|
|
38
|
-
self.token = os.environ.get("GOOGLE_TOKEN", c2cciutils.gopass("gs/ci/google_calendar/token"))
|
|
39
|
-
self.token_uri = os.environ.get(
|
|
40
|
-
"GOOGLE_TOKEN_URI", c2cciutils.gopass("gs/ci/google_calendar/token_uri")
|
|
41
|
-
)
|
|
42
|
-
self.refresh_token = os.environ.get(
|
|
43
|
-
"GOOGLE_REFRESH_TOKEN",
|
|
44
|
-
c2cciutils.gopass("gs/ci/google_calendar/refresh_token"),
|
|
45
|
-
)
|
|
46
|
-
self.client_id = os.environ.get(
|
|
47
|
-
"GOOGLE_CLIENT_ID", c2cciutils.gopass("gs/ci/google_calendar/client_id")
|
|
48
|
-
)
|
|
49
|
-
self.client_secret = os.environ.get(
|
|
50
|
-
"GOOGLE_CLIENT_SECRET",
|
|
51
|
-
c2cciutils.gopass("gs/ci/google_calendar/client_secret"),
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
self.creds: Credentials = self.init_calendar_service()
|
|
55
|
-
self._update_creds()
|
|
56
|
-
self.service = build("calendar", "v3", credentials=self.creds)
|
|
57
|
-
|
|
58
|
-
def init_calendar_service(self) -> Credentials: # type: ignore
|
|
59
|
-
"""Initialize the calendar service."""
|
|
60
|
-
# The file token pickle stores the user's access and refresh tokens, and is
|
|
61
|
-
# created automatically when the authorization flow completes for the first
|
|
62
|
-
# time.
|
|
63
|
-
if os.path.exists(self.credentials_pickle_file):
|
|
64
|
-
with open(self.credentials_pickle_file, "rb") as token:
|
|
65
|
-
creds = pickle.load(token) # noqa: S301 # nosec
|
|
66
|
-
# If there are no (valid) credentials available, let the user log in.
|
|
67
|
-
if not creds or not creds.valid: # pylint: disable=possibly-used-before-assignment
|
|
68
|
-
if creds and creds.expired and creds.refresh_token:
|
|
69
|
-
creds.refresh(Request()) # type: ignore
|
|
70
|
-
else:
|
|
71
|
-
if self.token:
|
|
72
|
-
creds = Credentials( # type: ignore
|
|
73
|
-
self.token,
|
|
74
|
-
refresh_token=self.refresh_token,
|
|
75
|
-
token_uri=self.token_uri,
|
|
76
|
-
client_id=self.client_id,
|
|
77
|
-
client_secret=self.client_secret,
|
|
78
|
-
scopes=self.scopes,
|
|
79
|
-
)
|
|
80
|
-
else:
|
|
81
|
-
flow = InstalledAppFlow.from_client_secrets_file(self.credentials_json_file, self.scopes)
|
|
82
|
-
creds = flow.run_local_server(port=0)
|
|
83
|
-
self.refresh_token = creds
|
|
84
|
-
|
|
85
|
-
# Save the credentials for the next run
|
|
86
|
-
with open(self.credentials_pickle_file, "wb") as token:
|
|
87
|
-
pickle.dump(creds, token)
|
|
88
|
-
|
|
89
|
-
def _update_creds(self) -> None:
|
|
90
|
-
"""Update the credentials."""
|
|
91
|
-
self.client_id = self.creds.client_id
|
|
92
|
-
self.client_secret = self.creds.client_secret
|
|
93
|
-
self.token = self.creds.token
|
|
94
|
-
self.token_uri = self.creds.token_uri
|
|
95
|
-
self.refresh_token = self.creds.refresh_token
|
|
96
|
-
|
|
97
|
-
def print_all_calendars(self) -> None:
|
|
98
|
-
"""Print all calendar events."""
|
|
99
|
-
# list all the calendars that the user has access to.
|
|
100
|
-
# used to debug credentials
|
|
101
|
-
print("Getting list of calendars")
|
|
102
|
-
calendars_result = self.service.calendarList().list().execute() # pylint: disable=no-member
|
|
103
|
-
|
|
104
|
-
calendars = calendars_result.get("items", [])
|
|
105
|
-
|
|
106
|
-
if not calendars:
|
|
107
|
-
print("::error::No calendars found.")
|
|
108
|
-
for calendar in calendars:
|
|
109
|
-
summary = calendar["summary"]
|
|
110
|
-
event_id = calendar["id"]
|
|
111
|
-
primary = "Primary" if calendar.get("primary") else ""
|
|
112
|
-
print(f"{summary}\t{event_id}\t{primary}")
|
|
113
|
-
|
|
114
|
-
def print_latest_events(self, time_min: Optional[datetime.datetime] = None) -> None:
|
|
115
|
-
"""
|
|
116
|
-
Print latest events.
|
|
117
|
-
|
|
118
|
-
Arguments:
|
|
119
|
-
time_min: The time to be considered.
|
|
120
|
-
|
|
121
|
-
"""
|
|
122
|
-
now = datetime.datetime.utcnow()
|
|
123
|
-
if not time_min:
|
|
124
|
-
time_min = datetime.datetime.utcnow() - datetime.timedelta(days=30)
|
|
125
|
-
events_result = (
|
|
126
|
-
self.service.events() # pylint: disable=no-member
|
|
127
|
-
.list(
|
|
128
|
-
calendarId=self.calendar_id,
|
|
129
|
-
timeMin=time_min.isoformat() + "Z",
|
|
130
|
-
timeMax=now.isoformat() + "Z",
|
|
131
|
-
singleEvents=True,
|
|
132
|
-
orderBy="startTime",
|
|
133
|
-
)
|
|
134
|
-
.execute()
|
|
135
|
-
)
|
|
136
|
-
events = events_result.get("items", [])
|
|
137
|
-
|
|
138
|
-
if not events:
|
|
139
|
-
print("::error::No upcoming events found.")
|
|
140
|
-
for event in events:
|
|
141
|
-
start = event["start"].get("dateTime", event["start"].get("date"))
|
|
142
|
-
print(start, event["summary"])
|
|
143
|
-
|
|
144
|
-
def create_event(
|
|
145
|
-
self,
|
|
146
|
-
summary: str = f"dummy/image:{datetime.datetime.now().isoformat()}",
|
|
147
|
-
description: str = "description",
|
|
148
|
-
) -> None:
|
|
149
|
-
"""
|
|
150
|
-
Create a calendar event.
|
|
151
|
-
|
|
152
|
-
Arguments:
|
|
153
|
-
summary: The event summary
|
|
154
|
-
description: The event description
|
|
155
|
-
|
|
156
|
-
"""
|
|
157
|
-
now = datetime.datetime.now()
|
|
158
|
-
start = now.isoformat()
|
|
159
|
-
end = (now + datetime.timedelta(minutes=15)).isoformat()
|
|
160
|
-
body = {
|
|
161
|
-
"summary": summary,
|
|
162
|
-
"description": description,
|
|
163
|
-
"start": {"dateTime": start, "timeZone": "Europe/Zurich"},
|
|
164
|
-
"end": {"dateTime": end, "timeZone": "Europe/Zurich"},
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
event_result = self.service.events().insert(calendarId=self.calendar_id, body=body).execute() # pylint: disable=no-member
|
|
168
|
-
print(f"Created event with id: {event_result['id']}")
|
|
169
|
-
|
|
170
|
-
def save_credentials_to_gopass(self) -> None:
|
|
171
|
-
"""Save the calendar credentials to gopass."""
|
|
172
|
-
objects_to_save = {
|
|
173
|
-
"gs/ci/google_calendar/calendarId": self.calendar_id,
|
|
174
|
-
"gs/ci/google_calendar/token": self.token,
|
|
175
|
-
"gs/ci/google_calendar/token_uri": self.token_uri,
|
|
176
|
-
"gs/ci/google_calendar/refresh_token": self.refresh_token,
|
|
177
|
-
"gs/ci/google_calendar/client_id": self.client_id,
|
|
178
|
-
"gs/ci/google_calendar/client_secret": self.client_secret,
|
|
179
|
-
}
|
|
180
|
-
for key, secret in objects_to_save.items():
|
|
181
|
-
assert secret is not None
|
|
182
|
-
c2cciutils.gopass_put(secret, key)
|
|
183
|
-
|
|
184
|
-
def __del__(self) -> None:
|
|
185
|
-
"""Delete the credentials file."""
|
|
186
|
-
if os.path.exists(self.credentials_pickle_file):
|
|
187
|
-
os.remove(self.credentials_pickle_file)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def main_calendar() -> None:
|
|
191
|
-
"""Run the calendar main function."""
|
|
192
|
-
parser = argparse.ArgumentParser(
|
|
193
|
-
description="Interact with google API for the Docker publishing calendar"
|
|
194
|
-
)
|
|
195
|
-
parser.add_argument(
|
|
196
|
-
"--refresh-gopass-credentials",
|
|
197
|
-
action="store_true",
|
|
198
|
-
help="Refresh the credentials in gopass using google API",
|
|
199
|
-
)
|
|
200
|
-
parser.add_argument(
|
|
201
|
-
"--show-events-since",
|
|
202
|
-
help="show the calendar events since a date in 'YYYY-mm-dd' format",
|
|
203
|
-
type=lambda s: datetime.datetime.strptime(s, "%Y-%m-%d"),
|
|
204
|
-
)
|
|
205
|
-
parser.add_argument(
|
|
206
|
-
"--create-test-event",
|
|
207
|
-
action="store_true",
|
|
208
|
-
help="Create a dummy event to check that the calendar settings are correct",
|
|
209
|
-
)
|
|
210
|
-
args = parser.parse_args()
|
|
211
|
-
|
|
212
|
-
if args.show_events_since or args.refresh_gopass_credentials or args.create_test_event:
|
|
213
|
-
google_calendar = GoogleCalendar()
|
|
214
|
-
else:
|
|
215
|
-
parser.print_help()
|
|
216
|
-
|
|
217
|
-
if args.show_events_since:
|
|
218
|
-
google_calendar.print_latest_events( # pylint: disable=possibly-used-before-assignment
|
|
219
|
-
args.show_events_since
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
if args.refresh_gopass_credentials:
|
|
223
|
-
google_calendar.save_credentials_to_gopass()
|
|
224
|
-
|
|
225
|
-
if args.create_test_event:
|
|
226
|
-
google_calendar.create_event()
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def pip(
|
|
230
|
-
package: c2cciutils.configuration.PublishPypiPackage, version: str, version_type: str, publish: bool
|
|
231
|
-
) -> bool:
|
|
232
|
-
"""
|
|
233
|
-
Publish to pypi.
|
|
234
|
-
|
|
235
|
-
Arguments:
|
|
236
|
-
version: The version that will be published
|
|
237
|
-
version_type: Describe the kind of release we do: rebuild (specified using --type), version_tag,
|
|
238
|
-
version_branch, feature_branch, feature_tag (for pull request)
|
|
239
|
-
publish: If False only check the package
|
|
240
|
-
package: The package configuration
|
|
241
|
-
|
|
242
|
-
"""
|
|
243
|
-
print(f"::group::{'Publishing' if publish else 'Checking'} '{package.get('path')}' to pypi")
|
|
244
|
-
sys.stdout.flush()
|
|
245
|
-
sys.stderr.flush()
|
|
246
|
-
|
|
247
|
-
try:
|
|
248
|
-
env = {}
|
|
249
|
-
env["VERSION"] = version
|
|
250
|
-
env["VERSION_TYPE"] = version_type
|
|
251
|
-
full_repo = c2cciutils.get_repository()
|
|
252
|
-
full_repo_split = full_repo.split("/")
|
|
253
|
-
master_branch, _ = c2cciutils.get_master_branch(full_repo_split)
|
|
254
|
-
is_master = master_branch == version
|
|
255
|
-
env["IS_MASTER"] = "TRUE" if is_master else "FALSE"
|
|
256
|
-
|
|
257
|
-
cwd = os.path.abspath(package.get("path", "."))
|
|
258
|
-
|
|
259
|
-
dist = os.path.join(cwd, "dist")
|
|
260
|
-
if not os.path.exists(dist):
|
|
261
|
-
os.mkdir(dist)
|
|
262
|
-
if os.path.exists(os.path.join(cwd, "setup.py")):
|
|
263
|
-
cmd = ["python3", "./setup.py", "egg_info", "--no-date"]
|
|
264
|
-
cmd += (
|
|
265
|
-
["--tag-build=dev" + datetime.datetime.now().strftime("%Y%m%d%H%M%S")]
|
|
266
|
-
if version_type in ("version_branch", "rebuild")
|
|
267
|
-
else []
|
|
268
|
-
)
|
|
269
|
-
cmd.append("bdist_wheel")
|
|
270
|
-
else:
|
|
271
|
-
if not os.path.exists(dist):
|
|
272
|
-
os.mkdir(dist)
|
|
273
|
-
cmd = ["pip", "wheel", "--no-deps", "--wheel-dir=dist", "."]
|
|
274
|
-
if os.path.exists(os.path.join(cwd, "pyproject.toml")):
|
|
275
|
-
use_poetry = False
|
|
276
|
-
if "build_command" not in package:
|
|
277
|
-
with open(os.path.join(cwd, "pyproject.toml"), "rb") as project_file:
|
|
278
|
-
pyproject = tomllib.load(project_file)
|
|
279
|
-
re_splitter = re.compile(r"[<>=]+")
|
|
280
|
-
for requirement in pyproject.get("build-system", {}).get("requires", []):
|
|
281
|
-
requirement_split = re_splitter.split(requirement)
|
|
282
|
-
if requirement_split[0] in ("poetry", "poetry-core"):
|
|
283
|
-
use_poetry = True
|
|
284
|
-
break
|
|
285
|
-
subprocess.run(
|
|
286
|
-
["pip", "install", *pyproject.get("build-system", {}).get("requires", [])], check=True
|
|
287
|
-
)
|
|
288
|
-
if use_poetry:
|
|
289
|
-
freeze = subprocess.run(["pip", "freeze"], check=True, stdout=subprocess.PIPE)
|
|
290
|
-
for freeze_line in freeze.stdout.decode("utf-8").split("\n"):
|
|
291
|
-
if freeze_line.startswith("poetry-") or freeze_line.startswith("poetry="):
|
|
292
|
-
print(freeze_line)
|
|
293
|
-
env_bash = " ".join([f"{key}={value}" for key, value in env.items()])
|
|
294
|
-
print(f"Run in {cwd}: {env_bash} poetry build")
|
|
295
|
-
sys.stdout.flush()
|
|
296
|
-
sys.stderr.flush()
|
|
297
|
-
subprocess.run(["poetry", "build"], cwd=cwd, env={**os.environ, **env}, check=True)
|
|
298
|
-
cmd = []
|
|
299
|
-
if cmd:
|
|
300
|
-
cmd = package.get("build_command", cmd)
|
|
301
|
-
subprocess.check_call(cmd, cwd=cwd, env=env)
|
|
302
|
-
cmd = ["twine"]
|
|
303
|
-
cmd += ["upload", "--verbose", "--disable-progress-bar"] if publish else ["check"]
|
|
304
|
-
cmd += glob.glob(os.path.join(cwd, "dist/*.whl"))
|
|
305
|
-
cmd += glob.glob(os.path.join(cwd, "dist/*.tar.gz"))
|
|
306
|
-
subprocess.check_call(cmd)
|
|
307
|
-
print("::endgroup::")
|
|
308
|
-
except subprocess.CalledProcessError as exception:
|
|
309
|
-
print(f"Error: {exception}")
|
|
310
|
-
print("::endgroup::")
|
|
311
|
-
print("::error::With error")
|
|
312
|
-
return False
|
|
313
|
-
return True
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
def docker(
|
|
317
|
-
config: c2cciutils.configuration.PublishDockerRepository,
|
|
318
|
-
name: str,
|
|
319
|
-
image_config: c2cciutils.configuration.PublishDockerImage,
|
|
320
|
-
tag_src: str,
|
|
321
|
-
dst_tags: list[str],
|
|
322
|
-
images_full: list[str],
|
|
323
|
-
) -> bool:
|
|
324
|
-
"""
|
|
325
|
-
Publish to a Docker registry.
|
|
326
|
-
|
|
327
|
-
config is like:
|
|
328
|
-
server: # The server fqdn
|
|
329
|
-
|
|
330
|
-
image_config is like:
|
|
331
|
-
name: # The image name
|
|
332
|
-
|
|
333
|
-
Arguments:
|
|
334
|
-
config: The publishing config
|
|
335
|
-
name: The repository name, just used to print messages
|
|
336
|
-
image_config: The image config
|
|
337
|
-
tag_src: The source tag (usually latest)
|
|
338
|
-
dst_tags: Publish using the provided tags
|
|
339
|
-
images_full: The list of published images (with tag), used to build the dispatch event
|
|
340
|
-
|
|
341
|
-
"""
|
|
342
|
-
print(
|
|
343
|
-
f"::group::Publishing {image_config['name']} to the server {name} using the tags {', '.join(dst_tags)}"
|
|
344
|
-
)
|
|
345
|
-
sys.stdout.flush()
|
|
346
|
-
sys.stderr.flush()
|
|
347
|
-
|
|
348
|
-
try:
|
|
349
|
-
new_images_full = []
|
|
350
|
-
if "server" in config:
|
|
351
|
-
for tag in dst_tags:
|
|
352
|
-
subprocess.run(
|
|
353
|
-
[
|
|
354
|
-
"docker",
|
|
355
|
-
"tag",
|
|
356
|
-
f"{image_config['name']}:{tag_src}",
|
|
357
|
-
f"{config['server']}/{image_config['name']}:{tag}",
|
|
358
|
-
],
|
|
359
|
-
check=True,
|
|
360
|
-
)
|
|
361
|
-
new_images_full.append(f"{config['server']}/{image_config['name']}:{tag}")
|
|
362
|
-
else:
|
|
363
|
-
for tag in dst_tags:
|
|
364
|
-
if tag_src != tag:
|
|
365
|
-
subprocess.run(
|
|
366
|
-
[
|
|
367
|
-
"docker",
|
|
368
|
-
"tag",
|
|
369
|
-
f"{image_config['name']}:{tag_src}",
|
|
370
|
-
f"{image_config['name']}:{tag}",
|
|
371
|
-
],
|
|
372
|
-
check=True,
|
|
373
|
-
)
|
|
374
|
-
new_images_full.append(f"{image_config['name']}:{tag}")
|
|
375
|
-
|
|
376
|
-
for image in new_images_full:
|
|
377
|
-
subprocess.run(["docker", "push", image], check=True)
|
|
378
|
-
images_full += new_images_full
|
|
379
|
-
|
|
380
|
-
print("::endgroup::")
|
|
381
|
-
except subprocess.CalledProcessError as exception:
|
|
382
|
-
print(f"Error: {exception}")
|
|
383
|
-
print("::endgroup::")
|
|
384
|
-
print("::error::With error")
|
|
385
|
-
return False
|
|
386
|
-
return True
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
def helm(folder: str, version: str, owner: str, repo: str, commit_sha: str, token: str) -> bool:
|
|
390
|
-
"""
|
|
391
|
-
Publish to pypi.
|
|
392
|
-
|
|
393
|
-
Arguments:
|
|
394
|
-
folder: The folder to be published
|
|
395
|
-
version: The version that will be published
|
|
396
|
-
owner: The GitHub repository owner
|
|
397
|
-
repo: The GitHub repository name
|
|
398
|
-
commit_sha: The sha of the current commit
|
|
399
|
-
token: The GitHub token
|
|
400
|
-
|
|
401
|
-
"""
|
|
402
|
-
print(f"::group::Publishing Helm chart from '{folder}' to GitHub release")
|
|
403
|
-
sys.stdout.flush()
|
|
404
|
-
sys.stderr.flush()
|
|
405
|
-
|
|
406
|
-
try:
|
|
407
|
-
yaml_ = ruamel.yaml.YAML()
|
|
408
|
-
with open(os.path.join(folder, "Chart.yaml"), encoding="utf-8") as open_file:
|
|
409
|
-
chart = yaml_.load(open_file)
|
|
410
|
-
chart["version"] = version
|
|
411
|
-
with open(os.path.join(folder, "Chart.yaml"), "w", encoding="utf-8") as open_file:
|
|
412
|
-
yaml_.dump(chart, open_file)
|
|
413
|
-
for index, dependency in enumerate(chart.get("dependencies", [])):
|
|
414
|
-
if dependency["repository"].startswith("https://"):
|
|
415
|
-
subprocess.run(["helm", "repo", "add", str(index), dependency["repository"]], check=True)
|
|
416
|
-
|
|
417
|
-
subprocess.run(["cr", "package", folder], check=True)
|
|
418
|
-
subprocess.run(
|
|
419
|
-
[
|
|
420
|
-
"cr",
|
|
421
|
-
"upload",
|
|
422
|
-
f"--owner={owner}",
|
|
423
|
-
f"--git-repo={repo}",
|
|
424
|
-
f"--commit={commit_sha}",
|
|
425
|
-
"--release-name-template={{ .Version }}",
|
|
426
|
-
f"--token={token}",
|
|
427
|
-
],
|
|
428
|
-
check=True,
|
|
429
|
-
)
|
|
430
|
-
if not os.path.exists(".cr-index"):
|
|
431
|
-
os.mkdir(".cr-index")
|
|
432
|
-
subprocess.run(
|
|
433
|
-
[
|
|
434
|
-
"cr",
|
|
435
|
-
"index",
|
|
436
|
-
f"--owner={owner}",
|
|
437
|
-
f"--git-repo={repo}",
|
|
438
|
-
f"--charts-repo=https://{owner}.github.io/{repo}",
|
|
439
|
-
"--push",
|
|
440
|
-
"--release-name-template={{ .Version }}",
|
|
441
|
-
f"--token={token}",
|
|
442
|
-
],
|
|
443
|
-
check=True,
|
|
444
|
-
)
|
|
445
|
-
print("::endgroup::")
|
|
446
|
-
except subprocess.CalledProcessError as exception:
|
|
447
|
-
print(f"Error: {exception}")
|
|
448
|
-
print("::endgroup::")
|
|
449
|
-
print("::error::With error")
|
|
450
|
-
return False
|
|
451
|
-
return True
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema",
|
|
3
|
-
"$id": "https://raw.githubusercontent.com/camptocamp/tilecloud-chain/master/tilecloud_chain/schema.json",
|
|
4
|
-
"title": "Applications configuration",
|
|
5
|
-
"description": "All the applications configuration",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"definitions": {},
|
|
8
|
-
"additionalProperties": {
|
|
9
|
-
"title": "Application configuration",
|
|
10
|
-
"description": "An application configuration",
|
|
11
|
-
"type": "object",
|
|
12
|
-
"properties": {
|
|
13
|
-
"url-pattern": {
|
|
14
|
-
"title": "URL pattern",
|
|
15
|
-
"description": "URL pattern, to be used for files that didn't come from GitHub release, available arguments: {version}",
|
|
16
|
-
"type": "string"
|
|
17
|
-
},
|
|
18
|
-
"type": {
|
|
19
|
-
"title": "The type of file",
|
|
20
|
-
"description": "The type of file",
|
|
21
|
-
"type": "string",
|
|
22
|
-
"enum": ["tar"]
|
|
23
|
-
},
|
|
24
|
-
"get-file-name": {
|
|
25
|
-
"title": "The filename to get",
|
|
26
|
-
"description": "The name of the file to get in the GitHub release",
|
|
27
|
-
"type": "string"
|
|
28
|
-
},
|
|
29
|
-
"to-file-name": {
|
|
30
|
-
"title": "The created tile name",
|
|
31
|
-
"description": "The name of the final tile we will create",
|
|
32
|
-
"type": "string"
|
|
33
|
-
},
|
|
34
|
-
"tar-file-name": {
|
|
35
|
-
"title": "The tile name to get in the tar file",
|
|
36
|
-
"type": "string"
|
|
37
|
-
},
|
|
38
|
-
"finish-commands": {
|
|
39
|
-
"title": "The commands to run after the tile creation",
|
|
40
|
-
"type": "array",
|
|
41
|
-
"items": {
|
|
42
|
-
"type": "array",
|
|
43
|
-
"items": {
|
|
44
|
-
"type": "string"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
c2cciutils/scripts/clean.py
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
"""The clean main function."""
|
|
4
|
-
|
|
5
|
-
import argparse
|
|
6
|
-
import json
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
from typing import cast
|
|
10
|
-
|
|
11
|
-
import requests
|
|
12
|
-
import yaml
|
|
13
|
-
|
|
14
|
-
import c2cciutils
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def clean(image: str, tag: str, token: str) -> None:
|
|
18
|
-
"""
|
|
19
|
-
Delete an image from Docker hub.
|
|
20
|
-
|
|
21
|
-
Arguments:
|
|
22
|
-
image: The image name that should be deleted (<organization>/<name>)
|
|
23
|
-
tag: The tag that should be deleted
|
|
24
|
-
token: The token used to be authenticated on Docker hub
|
|
25
|
-
|
|
26
|
-
"""
|
|
27
|
-
print(f"Delete image '{image}:{tag}'.")
|
|
28
|
-
|
|
29
|
-
response = requests.head(
|
|
30
|
-
f"https://hub.docker.com/v2/repositories/{image}/tags/{tag}/",
|
|
31
|
-
headers={"Authorization": "JWT " + token},
|
|
32
|
-
timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
|
|
33
|
-
)
|
|
34
|
-
if response.status_code == 404:
|
|
35
|
-
return
|
|
36
|
-
if not response.ok:
|
|
37
|
-
print(f"Error checking image '{image}:{tag}' status.")
|
|
38
|
-
print(response.text)
|
|
39
|
-
sys.exit(1)
|
|
40
|
-
|
|
41
|
-
response = requests.delete(
|
|
42
|
-
f"https://hub.docker.com/v2/repositories/{image}/tags/{tag}/",
|
|
43
|
-
headers={"Authorization": "JWT " + token},
|
|
44
|
-
timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
|
|
45
|
-
)
|
|
46
|
-
if not response.ok:
|
|
47
|
-
print("::error::Error on deleting tag: " + tag)
|
|
48
|
-
print(response.text)
|
|
49
|
-
sys.exit(1)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def main() -> None:
|
|
53
|
-
"""Run the main function."""
|
|
54
|
-
parser = argparse.ArgumentParser(
|
|
55
|
-
description=(
|
|
56
|
-
"Clean the Docker images on Docker Hub for the branch we delete "
|
|
57
|
-
"(get from the GitHub event information)."
|
|
58
|
-
)
|
|
59
|
-
)
|
|
60
|
-
parser.parse_args()
|
|
61
|
-
|
|
62
|
-
username = (
|
|
63
|
-
os.environ["DOCKERHUB_USERNAME"]
|
|
64
|
-
if "DOCKERHUB_USERNAME" in os.environ
|
|
65
|
-
else c2cciutils.gopass("gs/ci/dockerhub/username")
|
|
66
|
-
)
|
|
67
|
-
password = (
|
|
68
|
-
os.environ["DOCKERHUB_PASSWORD"]
|
|
69
|
-
if "DOCKERHUB_PASSWORD" in os.environ
|
|
70
|
-
else c2cciutils.gopass("gs/ci/dockerhub/password")
|
|
71
|
-
)
|
|
72
|
-
token = requests.post(
|
|
73
|
-
"https://hub.docker.com/v2/users/login/",
|
|
74
|
-
headers={"Content-Type": "application/json"},
|
|
75
|
-
data=json.dumps(
|
|
76
|
-
{
|
|
77
|
-
"username": username,
|
|
78
|
-
"password": password,
|
|
79
|
-
}
|
|
80
|
-
),
|
|
81
|
-
timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
|
|
82
|
-
).json()["token"]
|
|
83
|
-
|
|
84
|
-
with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as event_file:
|
|
85
|
-
event = json.loads(event_file.read())
|
|
86
|
-
print(yaml.dump(event))
|
|
87
|
-
ref = str(event["number"]) if "pull_request" in event else event["ref"]
|
|
88
|
-
|
|
89
|
-
ref = ref.replace("/", "_")
|
|
90
|
-
|
|
91
|
-
config = c2cciutils.get_config()
|
|
92
|
-
|
|
93
|
-
docker_config = cast(
|
|
94
|
-
c2cciutils.configuration.PublishDockerConfig,
|
|
95
|
-
config.get("publish", {}).get("docker", {}) if config.get("publish", {}).get("docker", False) else {},
|
|
96
|
-
)
|
|
97
|
-
for image in docker_config.get("images", []):
|
|
98
|
-
for tag in image.get("tags", []):
|
|
99
|
-
clean(image["name"], tag.format(version=ref), token)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if __name__ == "__main__":
|
|
103
|
-
main()
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
|
|
3
|
-
import yaml
|
|
4
|
-
|
|
5
|
-
import c2cciutils.lib.docker
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def main() -> None:
|
|
9
|
-
"""Dump the actual versions of packages in image to file ci/dpkg-versions.yaml."""
|
|
10
|
-
argparser = argparse.ArgumentParser(
|
|
11
|
-
description="Dump the actual versions of packages in image to file ci/dpkg-versions.yaml."
|
|
12
|
-
)
|
|
13
|
-
argparser.add_argument("--distribution", help="The default distribution code to be used")
|
|
14
|
-
argparser.add_argument("--release", help="The default release version to be used")
|
|
15
|
-
argparser.add_argument("images", help="The image to check", nargs="+")
|
|
16
|
-
args = argparser.parse_args()
|
|
17
|
-
|
|
18
|
-
versions_config, _ = c2cciutils.lib.docker.get_versions_config()
|
|
19
|
-
for image in args.images:
|
|
20
|
-
_, versions_image = c2cciutils.lib.docker.get_dpkg_packages_versions(
|
|
21
|
-
image,
|
|
22
|
-
default_distribution=args.distribution,
|
|
23
|
-
default_release=args.release,
|
|
24
|
-
)
|
|
25
|
-
versions_config[image] = {k: str(v) for k, v in versions_image.items()}
|
|
26
|
-
|
|
27
|
-
with open("ci/dpkg-versions.yaml", "w", encoding="utf-8") as versions_file:
|
|
28
|
-
versions_file.write("# See repository list: https://repology.org/repositories/statistics\n\n")
|
|
29
|
-
versions_file.write(yaml.dump(versions_config, Dumper=yaml.SafeDumper, default_flow_style=False))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if __name__ == "__main__":
|
|
33
|
-
main()
|
c2cciutils/scripts/pin_pipenv.py
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
import configparser
|
|
6
|
-
import json
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def main() -> None:
|
|
10
|
-
"""Run the command."""
|
|
11
|
-
parser = argparse.ArgumentParser(
|
|
12
|
-
description="""Output packages with versions from Pipfile.lock in Pipfile format (similar to pip freeze).
|
|
13
|
-
Useful to pin all the dependency in the Pipfile, on stabilization branch to be able to upgrade one package that have a security issue."""
|
|
14
|
-
)
|
|
15
|
-
parser.add_argument("--packages", action="store_true", help="Output only the packages section")
|
|
16
|
-
parser.add_argument("--dev-packages", action="store_true", help="Output only the dev-packages section")
|
|
17
|
-
parser.add_argument("--pipfile", default="Pipfile", help="The base Pipfile filename")
|
|
18
|
-
args = parser.parse_args()
|
|
19
|
-
|
|
20
|
-
packages = {}
|
|
21
|
-
dev_packages = {}
|
|
22
|
-
|
|
23
|
-
with open(args.pipfile + ".lock", encoding="utf-8") as pipfilelock_file:
|
|
24
|
-
pipfilelock = json.loads(pipfilelock_file.read())
|
|
25
|
-
for pkg, pkg_config in pipfilelock["default"].items():
|
|
26
|
-
packages[pkg] = pkg_config["version"]
|
|
27
|
-
for pkg, pkg_config in pipfilelock["develop"].items():
|
|
28
|
-
dev_packages[pkg] = pkg_config["version"]
|
|
29
|
-
|
|
30
|
-
config = configparser.ConfigParser()
|
|
31
|
-
config.read(args.pipfile)
|
|
32
|
-
|
|
33
|
-
if args.packages or not args.packages and not args.dev_packages:
|
|
34
|
-
print("[packages]")
|
|
35
|
-
print("# Lock dependencies")
|
|
36
|
-
for pkg, version in packages.items():
|
|
37
|
-
if pkg not in config["packages"] and f'"{pkg}"' not in config["packages"]:
|
|
38
|
-
quote = '"' if "." in pkg else ""
|
|
39
|
-
print(f'{quote}{pkg}{quote} = "{version}"')
|
|
40
|
-
|
|
41
|
-
if args.packages and args.dev_packages or not args.packages and not args.dev_packages:
|
|
42
|
-
print()
|
|
43
|
-
|
|
44
|
-
if args.dev_packages or not args.packages and not args.dev_packages:
|
|
45
|
-
print("[dev-packages]")
|
|
46
|
-
print("# Lock dependencies")
|
|
47
|
-
for pkg, version in dev_packages.items():
|
|
48
|
-
if pkg not in config["dev-packages"] and f'"{pkg}"' not in config["dev-packages"]:
|
|
49
|
-
quote = '"' if "." in pkg else ""
|
|
50
|
-
print(f'{quote}{pkg}{quote} = "{version}"')
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if __name__ == "__main__":
|
|
54
|
-
main()
|