11#!/usr/bin/env node
22
3- const clone = require ( "git-clone" ) ;
43const axios = require ( "axios" ) . default ;
5- const fs = require ( "fs-extra" ) ;
64const chalk = require ( "chalk" ) ;
7- const objChange = require ( "on-change" ) ;
85const cliProgress = require ( "cli-progress" ) ;
96const argv = require ( "yargs" ) ;
7+ const shell = require ( "shelljs" ) ;
108const Utils = require ( "./utils" ) ;
9+ const getRepos = require ( "./getRepos" ) ;
1110
1211/**
1312 * define script options.
3332
3433if ( ! argv . argv . token ) {
3534 console . log (
36- chalk . bgRed (
37- "\n Please pass your gitlab personal access token. Check README.md to how grab it. \n"
35+ chalk . red (
36+ "\nPlease pass your gitlab personal access token. Check README.md to how grab it. \n"
3837 )
3938 ) ;
4039 process . exit ( 0 ) ;
4140}
4241
42+ /**
43+ * check for git commands exist.
44+ */
45+ if ( ! shell . which ( "git" ) ) {
46+ shell . echo ( `${ chalk . red ( "Sorry, this script requires git" ) } ` ) ;
47+ shell . exit ( 1 ) ;
48+ }
49+
4350/**
4451 * defining our needs.
4552 */
46- const token = argv . argv . token || "" ;
47- const baseUrl = argv . argv . url || "https://gitlab.com" ;
48- const output = argv . argv . output || "./repos" ;
4953const pagination = 100 ; // currently maximum gitlab pagination supports.
5054const defaultAddress = `/api/v4/projects?simple=true&membership=true&pagination=keyset&order_by=id&sort=asc&per_page=${ pagination } ` ;
5155const bar = new cliProgress . SingleBar (
5256 {
53- format : "progress [{bar}] {percentage}% | {value}/{total}" ,
57+ hideCursor : true ,
58+ format :
59+ "\nprogress [{bar}] {percentage}% | {value}/{total} | this may take several minutes \n" ,
5460 } ,
5561 cliProgress . Presets . shades_classic
5662) ;
5763
5864/**
59- * for saving next paginated data url .
65+ * create an object for storing arguments and use it every where .
6066 */
61- let next ;
67+ const scriptOptions = {
68+ token : argv . argv . token || "" ,
69+ baseUrl : argv . argv . url || "https://gitlab.com" ,
70+ output : argv . argv . output || "./repos" ,
71+ } ;
6272
6373/**
64- * total repository for handling progress bar .
74+ * for saving next paginated data url .
6575 */
66- let total = 0 ;
76+ let next ;
6777
6878/**
69- * to indicate when first cloning starts .
79+ * total repository for handling progress bar .
7080 */
71- let firstStart = true ;
72-
73- axios . defaults . baseURL = baseUrl ;
74- axios . defaults . headers . common [ "PRIVATE-TOKEN" ] = token ;
75-
76- if ( ! fs . existsSync ( output ) ) {
77- fs . mkdirSync ( output ) ;
78- }
81+ const totalRepos = [ ] ;
7982
80- /**
81- * listen for changes on cloned repos and we reached end of pagination or not.
82- */
83- const observer = objChange (
84- {
85- cloned : 0 ,
86- hasNext : true ,
87- } ,
88- ( ) => {
89- /**
90- * if we cloned all repos based on total and cloned and also there is no link for next paginated data, so we cloned all repos and should stop progress bar and cleanup message.
91- */
92- if ( observer . cloned === total && ! observer . hasNext ) {
93- bar . stop ( ) ;
94- console . log ( chalk . green ( `\n ${ total } repo(s) saved!! \n` ) ) ;
95- }
96- }
97- ) ;
83+ axios . defaults . baseURL = scriptOptions . baseUrl ;
84+ axios . defaults . headers . common [ "PRIVATE-TOKEN" ] = scriptOptions . token ;
9885
9986/**
10087 * generate our uitls.
10188 */
102- const utils = new Utils ( {
103- token,
104- url : baseUrl ,
105- output,
106- bar,
107- observer,
108- } ) ;
89+ const utils = new Utils ( bar , scriptOptions ) ;
10990
11091/**
11192 * main function:
@@ -119,59 +100,15 @@ function main() {
119100 . then ( ( res ) => {
120101 const repos = res . data ;
121102 const { length } = repos ;
122- total += length ;
123103
124104 /**
125105 * based on gitlab pagination document, the next url to be called come here, so we grab it and save it
126106 * to handle our pagination process.
127107 */
128108 const { link } = res . headers ;
129109
130- if ( firstStart ) {
131- /**
132- * so at the beginning of cloning we start our cli progress.
133- */
134- bar . start ( total , 0 ) ;
135-
136- firstStart = false ;
137- } else {
138- /**
139- * we update our total repos because of in new paginated data we should update total repos.
140- */
141- bar . setTotal ( total ) ;
142- }
143-
144110 for ( let i = 0 ; i < length ; i += 1 ) {
145- const repo = repos [ i ] ;
146- const {
147- name_with_namespace : nameWithNameSpace ,
148- http_url_to_repo : httpUrlToRepo ,
149- } = repo ;
150-
151- const repoName = Utils . generateRepoName ( nameWithNameSpace ) ;
152- const repoNameColor = Utils . generateRepoNameColorized ( repoName ) ;
153- const repoUrl = utils . generateRepoUrl ( httpUrlToRepo ) ;
154-
155- /**
156- * if we had already cloned this repo, we do action after cloning a repo without showing any message to update our process.
157- */
158- if ( utils . isRepoExist ( repoName ) ) {
159- utils . cloneCompleted ( repoNameColor , false ) ;
160- } else {
161- /**
162- * we start cloning the repo
163- */
164- console . log ( chalk . yellow ( `\n cloning ${ repoNameColor } ... \n` ) ) ;
165-
166- clone ( `${ repoUrl } ` , `${ output } /${ repoName } ` , undefined , ( ) => {
167- /**
168- * here again, check if clone completed, do action after completing clone.
169- */
170- if ( utils . isRepoExist ( repoName ) ) {
171- utils . cloneCompleted ( repoNameColor ) ;
172- }
173- } ) ;
174- }
111+ totalRepos . push ( repos [ i ] ) ;
175112 }
176113
177114 /**
@@ -187,13 +124,29 @@ function main() {
187124 main ( ) ;
188125 } else {
189126 /**
190- * if we don't have any other repos, so we stop our pagination process.
127+ * if we don't have any other repos url, so we stop our pagination process and
128+ * start cloning the repositories.
191129 */
192- observer . hasNext = false ;
130+ getRepos ( totalRepos , utils , bar , scriptOptions )
131+ . then ( ( ) => {
132+ bar . stop ( ) ;
133+ console . clear ( ) ;
134+ console . log (
135+ chalk . green (
136+ `\n \n \n ${ totalRepos . length } repo(s) saved!! \n \n \n`
137+ )
138+ ) ;
139+ process . exit ( 0 ) ;
140+ } )
141+ . catch ( ( err ) => {
142+ console . log ( `\n ${ chalk . red ( err . message ) } ` ) ;
143+ process . exit ( 0 ) ;
144+ } ) ;
193145 }
194146 } )
195147 . catch ( ( err ) => {
196- console . log ( `\n ${ chalk . red ( `trace: ${ err . stack } ` ) } \n` ) ;
148+ console . log ( `\n${ chalk . red ( err . message ) } \n` ) ;
149+ console . log ( `\n${ chalk . red ( `trace: ${ err . stack } ` ) } \n` ) ;
197150 process . exit ( 0 ) ;
198151 } ) ;
199152}
0 commit comments