@@ -9,54 +9,319 @@ const menuName = new URL(import.meta.url).pathname.split('/').pop().replace('.js
99const locale = client . locale . lib . menus [ menuName ] ;
1010
1111// Exports a default function
12- export default async ( beforeError ) => {
12+ export default async ( beforeError , forceUpdate ) => {
1313
1414 try {
1515
16+ // Stores the local configuration from the configuration file
17+ let localConfig = require ( './config.json' ) ;
18+
19+ // Function to show the post-update menu
20+ async function showPostUpdateMenu ( ) {
21+
22+ // Shows the select menu
23+ global . currentPrompt = select ( {
24+ message : `${ locale . promptMessage } :` ,
25+ choices : [
26+ {
27+ name : `🔎 ${ locale . choices . checkAgain } ` ,
28+ value : 'checkAgain'
29+ } ,
30+ {
31+ name : `${ localConfig . betaEnabled ? `🏠 ${ locale . choices . switchToStable } ` : `🧪 ${ locale . choices . switchToBeta } ` } ` ,
32+ value : 'switchVersion'
33+ } ,
34+ {
35+ name : `↩️ ${ locale . choices . return } ` ,
36+ value : 'return'
37+ }
38+ ] ,
39+ } ) ;
40+
41+ // When the user selects an option
42+ global . currentPrompt . then ( async ( result ) => {
43+
44+ // Switches between the options
45+ switch ( result ) {
46+
47+ // If the user wants to check again for updates
48+ case 'checkAgain' :
49+
50+ // Shows this menu again
51+ await client . functions . menus . update ( ) ;
52+
53+ // Breaks the switch
54+ break ;
55+
56+ // If the user wants to change it's version
57+ case 'switchVersion' :
58+
59+ // Changes the betaEnabled value
60+ localConfig . betaEnabled = localConfig . betaEnabled ? false : true ;
61+
62+ // Saves the new configuration
63+ await fs . writeFileSync ( './config.json' , JSON . stringify ( localConfig , null , 4 ) ) ;
64+
65+ // Shows this menu again, passing the forceUpdate parameter based on the new value
66+ await client . functions . menus . update ( null , localConfig . betaEnabled ? false : true ) ;
67+
68+ // Breaks the switch
69+ break ;
70+
71+ // If the user wants to go back to the main menu
72+ case 'return' :
73+
74+ // Shows the main menu
75+ await client . functions . menus . main ( ) ;
76+
77+ // Breaks the switch
78+ break ;
79+ } ;
80+
81+ // When an error occurs
82+ } ) . catch ( async ( error ) => {
83+
84+ // Runs this menu again, passing the error
85+ await client . functions . menus [ menuName ] ( error ) ;
86+ } ) ;
87+ } ;
88+
1689 // Cleans the console and shows the logo
1790 process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
1891 await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
19-
92+
2093 // Shows an error message if one occurred
2194 if ( beforeError ) console . log ( `❌ ${ locale . errorMessage } .\n` ) ;
2295 if ( beforeError && process . env . NODE_ENV !== 'production' ) logger . error ( `${ beforeError . stack } \n` ) ;
96+
97+ try {
98+
99+ // Shows a message indicating that the bot is checking for updates
100+ console . log ( `🔎 ${ locale . checkingForUpdates } ...` ) ;
23101
24- // Shows a default text
25- console . log ( '🚧 This section is currently under development.\n ') ;
102+ // Loads the repository configuration
103+ const packageConfig = require ( './package.json ') ;
26104
27- // Shows the select menu
28- global . currentPrompt = select ( {
29- message : `${ locale . promptMessage } :` ,
30- choices : [
31- {
32- name : `↩️ ${ locale . choices . return } ` ,
33- value : 'return'
34- }
35- ] ,
36- } ) ;
105+ // Sets the latest local tag as the current version from the package
106+ let latestLocalTag = packageConfig . version ;
107+
108+ // Imports the necessary libraries
109+ const simpleGit = require ( 'simple-git' ) ;
37110
38- // When the user selects an option
39- global . currentPrompt . then ( async ( result ) => {
111+ // Creates a new instance of simple-git
112+ const git = simpleGit ( ) ;
40113
41- // When the user selects an option
42- switch ( result ) {
114+ // Fetches the latest tags and prunes the old tags
115+ await git . fetch ( [ '--prune' , '--tags' ] ) ;
116+
117+ // Gets the remote tags list
118+ const remoteTagLines = ( await git . listRemote ( [ '--tags' ] ) ) . split ( '\n' ) ;
119+
120+ // Maps the remote tags list to an array of tag names
121+ let remoteTags = remoteTagLines . map ( line => {
122+
123+ // Extracts the tag name from the line
124+ const match = line . match ( / r e f s \/ t a g s \/ ( .+ ) $ / ) ;
125+
126+ // Returns the tag name or null if it doesn't exist
127+ return match ? match [ 1 ] : null ;
128+
129+ // Filters out null values
130+ } ) . filter ( tag => tag !== null ) ;
131+
132+ // Gets the local tags list and filters out empty values
133+ const localTags = ( await git . tag ( [ '--list' ] ) ) . split ( '\n' ) . filter ( tag => tag . trim ( ) !== '' ) ;
134+
135+ // Filters out tags that exist locally but not remotely
136+ const tagsToDelete = localTags . filter ( tag => ! remoteTags . includes ( tag ) && tag ) ;
137+
138+ // Deletes these non-existent tags
139+ for ( const tag of tagsToDelete ) await git . tag ( [ '-d' , tag ] ) ;
140+
141+ // If the beta versions are disabled, removes them from the array
142+ if ( remoteTags && ! localConfig . betaEnabled ) remoteTags = remoteTags . filter ( tag => ! tag . includes ( 'beta' ) ) ;
143+
144+ // Obtains the latest remote tag
145+ const latestRemoteTag = remoteTags [ remoteTags . length - 1 ] ;
146+
147+ // Compares the local and remote tags
148+ if ( latestRemoteTag && latestRemoteTag . length > 0 && latestLocalTag !== latestRemoteTag ) {
149+
150+ // Function to update the bot
151+ async function updateBot ( ) {
152+
153+ // Cleans the console and shows the logo
154+ process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
155+ await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
156+
157+ // Shows a message indicating that the bot is checking for updates
158+ console . log ( `🔄 ${ await client . functions . utils . parseLocale ( locale . updatingFromTo , { originVersion : `v${ latestLocalTag } ` , targetVersion : `v${ latestRemoteTag } ` } ) } ...` ) ;
159+
160+ // Simulates a loading time
161+ await new Promise ( resolve => setTimeout ( resolve , 3000 ) ) ; // Espera de 3 segundos
162+
163+ // Makes a pull to update the bot
164+ //await git.pull();
165+
166+ // Makes a checkout to the latest tag
167+ //await git.checkout(latestTag);
168+
169+ // Cleans the console and shows the logo
170+ process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
171+ await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
172+
173+ // Shows a message indicating that the bot has been updated
174+ console . log ( `✅ ${ await client . functions . utils . parseLocale ( locale . updatedCorrectly , { targetVersion : `v${ latestRemoteTag } ` } ) } \n` ) ;
175+ } ;
176+
177+ // Shows a message indicating that there are new updates
178+ if ( ! forceUpdate ) {
179+
180+ // Function to obtain the release notes from the GitHub repository
181+ function getReleaseNotes ( owner , repository , tagName ) {
182+
183+ // Imports the necessary libraries
184+ const https = require ( 'https' ) ;
185+
186+ // Returns a promise to obtain the release notes
187+ return new Promise ( ( resolve , reject ) => {
188+ const options = {
189+ hostname : 'api.github.com' ,
190+ path : `/repos/${ owner } /${ repository } /releases/tags/${ tagName } ` ,
191+ method : 'GET' ,
192+ headers : {
193+ 'User-Agent' : 'NodeJS'
194+ }
195+ } ;
196+
197+ // Makes the request
198+ const request = https . request ( options , ( response ) => {
199+
200+ // Stores the data
201+ let data = '' ;
202+
203+ // When a chunk of data is received
204+ response . on ( 'data' , ( chunk ) => {
205+
206+ // Stores the chunk
207+ data += chunk ;
208+ } ) ;
209+
210+ // When the response ends
211+ response . on ( 'end' , ( ) => {
212+
213+ // If the response was OK
214+ if ( response . statusCode === 200 ) {
215+
216+ // Parses the data
217+ const jsonData = JSON . parse ( data ) ;
218+
219+ // Resolves the promise with the body of the response
220+ resolve ( jsonData . body ) ;
221+
222+ } else {
223+
224+ // Rejects the promise with the error
225+ if ( response . statusCode !== 404 ) return reject ( new Error ( `Received status code ${ response . statusCode } ` ) ) ;
226+
227+ // Resolves the promise with a default message
228+ resolve ( locale . noReleaseNotes ) ;
229+ } ;
230+ } ) ;
231+ } ) ;
232+
233+ // When an error occurs
234+ request . on ( 'error' , ( error ) => {
235+
236+ // Rejects the promise with the error
237+ reject ( error ) ;
238+ } ) ;
239+
240+ // Ends the request
241+ request . end ( ) ;
242+ } ) ;
243+ } ;
244+
245+ // Cleans the console and shows the logo
246+ process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
247+ await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
248+
249+ // Shows a message indicating that there are new updates
250+ console . log ( `⬇️ ${ await client . functions . utils . parseLocale ( locale . newVersionAvailable , { targetVersion : latestRemoteTag } ) } \n` ) ;
251+
252+ // Uses a regular expression to obtain the owner and repository name from the URL
253+ const repositoryMetadata = packageConfig . repository . url . match ( / g i t h u b \. c o m \/ ( [ ^ \/ ] + ) \/ ( [ ^ \/ ] + ) \. g i t / ) ;
254+
255+ // Stores the owner and repository name
256+ const repositoryOwner = repositoryMetadata [ 1 ] ;
257+ const repositoryName = repositoryMetadata [ 2 ] ;
258+
259+ // Obtains the release notes
260+ await getReleaseNotes ( repositoryOwner , repositoryName , latestRemoteTag ) . then ( releaseNotes => {
261+
262+ // Shows the release notes
263+ console . log ( `${ locale . releaseNotes } :\n${ releaseNotes } \n` ) ;
264+
265+ } ) . catch ( error => {
266+
267+ // Shows an error message if one occurred
268+ console . log ( `❌ ${ locale . releaseNotesError } \n` ) ;
43269
44- // If the user wants to go back to the main menu
45- case 'return' :
46-
47- // Shows the main menu
48- await client . functions . menus . main ( ) ;
270+ // Logs an error message if one occurred
271+ logger . error ( error ) ;
272+ } ) ;
273+
274+ // Shows the select menu to ask the user if wants to update the bot
275+ global . currentPrompt = select ( {
276+ message : `${ locale . updateConfirmationPromptMessage } :` ,
277+ choices : [
278+ {
279+ name : `✅ ${ locale . updateConfirmationChoices . yes } ` ,
280+ value : 'yes'
281+ } ,
282+ {
283+ name : `❌ ${ locale . updateConfirmationChoices . no } ` ,
284+ value : 'no'
285+ }
286+ ] ,
287+ } ) ;
288+
289+ // When the user selects an option
290+ await global . currentPrompt . then ( async ( result ) => {
291+
292+ // Cleans the console and shows the logo
293+ process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
294+ await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
295+
296+ // If the user wants to update the bot, updates it
297+ if ( result === 'yes' ) await updateBot ( ) ;
298+
299+ // When an error occurs
300+ } ) . catch ( async ( error ) => {
301+
302+ // Runs this menu again, passing the error
303+ await client . functions . menus [ menuName ] ( error ) ;
304+ } ) ;
305+ } ;
49306
50- // Breaks the switch
51- break ;
307+ } else {
308+
309+ // Cleans the console and shows the logo
310+ process . stdout . write ( '\u001b[2J\u001b[0;0H' ) ;
311+ await splashLogo ( client . locale . lib . loaders . splashLogo ) ;
312+
313+ // Shows a message indicating that the bot is updated to the latest version
314+ console . log ( `✅ ${ locale . alreadyUpdated } : v${ latestLocalTag } \n` ) ;
52315 } ;
53316
54- // When an error occurs
55- } ) . catch ( async ( error ) => {
317+ // Shows the post-update menu
318+ await showPostUpdateMenu ( ) ;
319+
320+ } catch ( error ) {
56321
57- // Runs this menu again, passing the error
58- await client . functions . menus [ menuName ] ( error ) ;
59- } ) ;
322+ // Shows an error message if one occurred
323+ console . error ( "❌ An error ocurred during the update process:" , error . stack ) ;
324+ } ;
60325
61326 } catch ( error ) {
62327
0 commit comments