11import json
2- import os
32import pathlib
43import subprocess
54
65import click
7- import dotenv
8- import requests
9-
106
117SCRIPTS_DIR = pathlib .Path (__file__ ).parent
12- dotenv .load_dotenv (SCRIPTS_DIR / '.env' )
13-
14- WEBLATE_PROJECT_WEB_URL = 'https://ds-wizard.org'
15-
16-
17- class WeblateClient :
18-
19- def __init__ (self , base_url : str , api_token : str ,
20- session : requests .Session | None = None ):
21- self .base_url = base_url .rstrip ('/' )
22- self .api_token = api_token
23- self .session = session or requests .Session ()
24- self .session .headers .update ({
25- 'Authorization' : f'Token { self .api_token } ' ,
26- })
27-
28- def _url (self , path : str ) -> str :
29- return f'{ self .base_url } /api/{ path } '
30-
31- def lock_component (self , project_slug : str , component_slug : str ) -> bool :
32- r = self .session .post (
33- url = self ._url (f'projects/{ project_slug } /components/{ component_slug } /lock/' ),
34- json = {
35- 'lock' : True ,
36- }
37- )
38- r .raise_for_status ()
39- return r .json ().get ('lock' , False )
40-
41- def get_project (self , project_slug : str ) -> dict :
42- r = self .session .get (
43- url = self ._url (f'projects/{ project_slug } /' ),
44- )
45- r .raise_for_status ()
46- return r .json ()
47-
48- def get_project_components (self , project_slug : str ) -> list [dict ]:
49- r = self .session .get (
50- url = self ._url (f'projects/{ project_slug } /components/' ),
51- )
52- r .raise_for_status ()
53- return r .json ().get ('results' , [])
54-
55- def create_project (self , name : str , slug : str ) -> dict :
56- r = self .session .post (
57- url = self ._url ('projects/' ),
58- json = {
59- 'name' : name ,
60- 'slug' : slug ,
61- 'web' : WEBLATE_PROJECT_WEB_URL ,
62- 'check_flags' : '' ,
63- 'translation_review' : False ,
64- 'source_review' : False ,
65- 'set_language_team' : True ,
66- 'instructions' : '' ,
67- 'enable_hooks' : True ,
68- 'language_aliases' : '' ,
69- 'secondary_language' : 0 ,
70- 'enforced_2fa' : False
71- },
72- )
73- r .raise_for_status ()
74- return r .json ()
75-
76- def create_component (self , project_slug : str , name : str , slug : str , branch : str ,
77- po_filemask : str , pot_file : str , repoweb : str ) -> dict :
78- r = self .session .post (
79- url = self ._url (f'projects/{ project_slug } /components/' ),
80- json = {
81- 'name' : name ,
82- 'slug' : slug ,
83- 'source_language' : {
84- 'code' : 'en' ,
85- 'name' : 'English' ,
86- 'plural' : {
87- 'source' : 0 ,
88- 'number' : 2 ,
89- 'formula' : 'n != 1'
90- },
91- 'direction' : 'ltr' ,
92- 'population' : 1728003224
93- },
94- 'vcs' : 'git' ,
95- 'repo' : 'git@github.com:ds-wizard/wizard-locales.git' ,
96- 'git_export' : f'https://localize.ds-wizard.org/git/{ project_slug } /{ slug } /' ,
97- 'branch' : branch ,
98- 'push_branch' : branch ,
99- 'filemask' : po_filemask ,
100- 'screenshot_filemask' : '' ,
101- 'template' : '' ,
102- 'edit_template' : True ,
103- 'intermediate' : '' ,
104- 'new_base' : pot_file ,
105- 'file_format' : 'po' ,
106- 'license' : 'CC-BY-4.0' ,
107- 'agreement' : '' ,
108- 'new_lang' : 'add' ,
109- 'language_code_style' : '' ,
110- 'push' : 'git@github.com:ds-wizard/wizard-locales.git' ,
111- 'check_flags' : '' ,
112- 'priority' : 100 ,
113- 'enforced_checks' : [],
114- 'restricted' : False ,
115- 'repoweb' : repoweb ,
116- 'report_source_bugs' : '' ,
117- 'merge_style' : 'rebase' ,
118- 'commit_message' : 'Translated using Weblate ({{ language_name }})\n \n Currently translated at {{ stats.translated_percent }}% ({{ stats.translated }} of {{ stats.all }} strings)\n \n Translation: {{ project_name }}/{{ component_name }}\n Translate-URL: {{ url }}' ,
119- 'add_message' : 'Added translation using Weblate ({{ language_name }})\n \n ' ,
120- 'delete_message' : 'Deleted translation using Weblate ({{ language_name }})\n \n ' ,
121- 'merge_message' : 'Merge branch \' {{ component_remote_branch }}\' into Weblate.\n \n ' ,
122- 'addon_message' : 'Update translation files\n \n Updated by \" {{ addon_name }}\" add-on in Weblate.\n \n Translation: {{ project_name }}/{{ component_name }}\n Translate-URL: {{ url }}' ,
123- 'pull_message' : 'Translations update from {{ site_title }}\n \n Translations update from [{{ site_title }}]({{ site_url }}) for [{{ project_name }}/{{ component_name }}]({{url}}).\n \n {% if component_linked_childs %}\n It also includes following components:\n {% for linked in component_linked_childs %}\n * [{{ linked.project_name }}/{{ linked.name }}]({{ linked.url }})\n {% endfor %}\n {% endif %}\n \n Current translation status:\n \n \n ' ,
124- "allow_translation_propagation" : True ,
125- "manage_units" : False ,
126- "enable_suggestions" : True ,
127- "suggestion_voting" : False ,
128- "suggestion_autoaccept" : 0 ,
129- 'push_on_commit' : True ,
130- 'commit_pending_age' : 24 ,
131- 'auto_lock_error' : True ,
132- 'language_regex' : '^[^.]+$' ,
133- 'key_filter' : '' ,
134- 'secondary_language' : None ,
135- 'variant_regex' : '' ,
136- 'zipfile' : '' ,
137- 'docfile' : '' ,
138- 'is_glossary' : False ,
139- 'glossary_color' : 'silver' ,
140- 'disable_autoshare' : True ,
141- 'category' : None ,
142- },
143- )
144- r .raise_for_status ()
145- return r .json ()
1468
1479
14810def _parse_version (version : str ) -> tuple [int , int , int ]:
@@ -153,6 +15,18 @@ def _parse_version(version: str) -> tuple[int, int, int]:
15315 return int (major ), int (minor ), int (patch )
15416
15517
18+ def _proceed ():
19+ proceed = False
20+ while not proceed :
21+ proceed = click .prompt (
22+ text = 'Are you ready to continue?' ,
23+ show_default = True ,
24+ type = bool ,
25+ default = True ,
26+ )
27+ click .echo ('=' * 60 )
28+
29+
15630def _run (* command : str ) -> None :
15731 click .echo (f'Running command: { ' ' .join (command )} ' )
15832 try :
@@ -165,88 +39,71 @@ def _run(*command: str) -> None:
16539 raise e
16640
16741
168- def _create_weblate_project (weblate_client : WeblateClient , project_name : str , project_slug : str ):
169- click .echo (f'Creating Weblate project "{ project_name } " with slug "{ project_slug } "' )
170- project = weblate_client .create_project (name = project_name , slug = project_slug )
171- click .echo (f'Created project: { json .dumps (project , indent = 2 )} ' )
172- client_component = weblate_client .create_component (
173- project_slug = project_slug ,
174- name = 'DSW Locales' ,
175- slug = 'dsw-locales' ,
176- branch = 'main' ,
177- po_filemask = 'locales/{locale}/LC_MESSAGES/dsw.po' ,
178- pot_file = 'locales/dsw.pot' ,
179- repoweb = 'https://localize.ds-wizard.org/git/{project_slug}/{component_slug}/' ,
180- )
181- mail_template_component = weblate_client .create_component (
182- project_slug = project_slug ,
183- name = 'DSW Mail Templates' ,
184- slug = 'dsw-mail-templates' ,
185- branch = 'main' ,
186- po_filemask = 'mail-templates/{locale}/LC_MESSAGES/dsw-mail-templates.po' ,
187- pot_file = 'mail-templates/dsw-mail-templates.pot' ,
188- repoweb = 'https://localize.ds-wizard.org/git/{project_slug}/{component_slug}/' ,
189- )
190- return project
191-
192-
19342def _release (version : str , locales_dir : pathlib .Path ):
194- weblate_client = WeblateClient (
195- base_url = os .getenv ('WEBLATE_BASE_URL' , '' ),
196- api_token = os .getenv ('WEBLATE_API_TOKEN' , '' ),
197- )
19843 major , minor , patch = _parse_version (version )
19944 # Prepare local environment
200- click .echo ('Locking changes in project on Weblate' )
201- # TODO: weblate lock (API only via all component)
202- click .echo ('Pushing changes from Weblate' )
203- # TODO: push changes from Weblate
204- click .echo ('Waiting for change propagation' )
205- click .echo ('Checking out the correct branch' )
45+ click .echo ('WEBLATE: Go to Weblate and ensure everything is synced and ready for release:' )
46+ localize_url = f'https://localize.ds-wizard.org/projects/dsw-{ major } -{ minor } /#repository'
47+ click .echo ('- 0 in pending' )
48+ click .echo ('- 0 in outgoing' )
49+ click .echo ('- 0 in missing' )
50+ click .echo ('- Lock components all components (click Lock button)' )
51+ click .echo (f'> { localize_url } ' )
52+ click .launch (localize_url )
53+ _proceed ()
54+
55+ # Wait for changes in Git
56+ click .echo ('GITHUB: Go to Git and ensure everything is up to date:' )
57+ commits_url = f'https://github.com/ds-wizard/wizard-locales/commits/v{ major } .{ minor } /'
58+ click .echo (f'> { commits_url } ' )
59+ click .launch (commits_url )
60+ click .echo ('REPO: Also verify that local git repository without any uncommitted changes.' )
61+ _proceed ()
62+
63+ # Checkout correct branch and pull latest changes
64+ click .echo ('REPO: Checking out the correct branch' )
20665 _run ('git' , 'checkout' , f'v{ major } .{ minor } ' )
207- click .echo ('Pulling latest changes' )
66+ click .echo ('REPO: Pulling latest changes' )
20867 _run ('git' , 'pull' , 'origin' , f'v{ major } .{ minor } ' )
20968
21069 # Update version in locale.json files
70+ click .echo ('REPO: Updating version in locale.json files' )
21171 langs = []
21272 for locale_dir in locales_dir .iterdir ():
21373 if not locale_dir .is_dir ():
21474 continue
21575 locale_id = locale_dir .name
21676 locale_json = locale_dir / 'locale.json'
21777 if not locale_json .is_file ():
218- click .echo (f'Warning: locale.json not found for locale { locale_id } , skipping' , err = True )
78+ click .echo (f'- Warning: locale.json not found for locale { locale_id } , skipping' , err = True )
21979 continue
22080 data = json .loads (locale_json .read_text (encoding = 'utf-8' ))
221- process = click .prompt (f'Do you want to release locale { locale_id } ?' ,
81+ process = click .prompt (f'> Do you want to release locale { locale_id } ?' ,
22282 show_default = True , type = bool , default = True )
22383 if not process :
224- click .echo (f'Skipping locale { locale_id } ' )
84+ click .echo (f'- Skipping locale { locale_id } ' )
22585 continue
22686 langs .append (locale_id )
227- click .echo (f'Processing locale { locale_id } ' )
87+ click .echo (f'- Processing locale { locale_id } ' )
22888 data ['version' ] = version
22989 data ['recommendedAppVersion' ] = f'{ major } .{ minor } .0'
23090 locale_json .write_text (json .dumps (data , indent = 2 , ensure_ascii = False ) + '\n ' , encoding = 'utf-8' )
231- click .echo (f'Updated version in { locale_json } ' )
91+ click .echo (f'- Updated version in { locale_json } ' )
23292
23393 # Let user do manual changes
234- click .echo ('You can now make any manual changes to the locale files if necessary.' )
235- proceed = False
236- while not proceed :
237- proceed = click .prompt ('Are you ready to continue with the release process?' ,
238- show_default = True , type = bool , default = True )
94+ click .echo ('REPO: You can now make any manual changes if necessary' )
95+ _proceed ()
23996
24097 # Commit and push changes
241- click .echo ('Committing all changes' )
98+ click .echo ('REPO: Committing all changes' )
24299 _run ('git' , 'add' , '-A' )
243100 _run ('git' , 'commit' , '-m' , f'Release { version } ({ ', ' .join (langs )} )' )
244- click .echo ('Pushing changes to remote' )
101+ click .echo ('REPO: Pushing changes to remote' )
245102 _run ('git' , 'push' , 'origin' , f'v{ major } .{ minor } ' )
246- click .echo ('Creating git tags' )
103+ click .echo ('REPO: Creating git tags' )
247104 for lang in langs :
248105 tag_name = f'v{ version } -{ lang } '
249- click .echo (f'Creating tag { tag_name } ' )
106+ click .echo (f'- Creating tag { tag_name } ' )
250107 _run ('git' , 'tag' , tag_name )
251108 _run ('git' , 'push' , 'origin' , tag_name )
252109
@@ -283,19 +140,5 @@ def prepare(old_version: str, new_version: str):
283140 ...
284141
285142
286- @cli .command ()
287- def test ():
288- weblate_client = WeblateClient (
289- base_url = os .getenv ('WEBLATE_BASE_URL' , '' ),
290- api_token = os .getenv ('WEBLATE_API_TOKEN' , '' ),
291- )
292- result = weblate_client .get_project ('dsw-4-25' )
293- print ('Project info:' )
294- print (json .dumps (result , indent = 2 ))
295- components = weblate_client .get_project_components ('dsw-4-25' )
296- print (f'Found { len (components )} components:' )
297- print (json .dumps (components , indent = 2 ))
298-
299-
300143if __name__ == '__main__' :
301144 cli ()
0 commit comments