1+ def  call (Map  config  =  [:]) {
2+     def  defaults =  [
3+         pipelines : ' scan_codebase'  ,
4+         outputFormats : ' json xlsx spdx cyclonedx'  ,
5+         inputsPath : ' scancode-inputs'  ,
6+         inputUrls : ' '  ,
7+         projectName : ' scancode-jenkins'  ,
8+         outputsArchiveName : ' scancode-outputs'  ,
9+         checkCompliance : false ,
10+         complianceFailLevel : ' ERROR'  ,
11+         complianceFailOnVulnerabilities : false ,
12+         pythonVersion : ' 3.12'  ,
13+         scancodeioBranch : ' ' 
14+     ]
15+ 
16+     def  settings =  defaults +  config
17+ 
18+     def  scanCodeEnv =  [
19+         " SECRET_KEY=${ generateSecretKey()} "  ,
20+         " SCANCODEIO_DB_NAME=scancodeio"  ,
21+         " SCANCODEIO_DB_USER=scancodeio"  , 
22+         " SCANCODEIO_DB_PASSWORD=scancodeio" 
23+     ]
24+     
25+     try  {
26+         stage(' Setup Environment'  ) {
27+             setupPython(settings. pythonVersion)
28+             setupPostgreSQL(scanCodeEnv)
29+             installScanCodeIO(settings. scancodeioBranch)
30+         }
31+         
32+         stage(' Prepare Database'  ) {
33+             withEnv(scanCodeEnv) {
34+                 sh ' scanpipe migrate --verbosity 0' 
35+             }
36+         }
37+         
38+         stage(' Create Project'  ) {
39+             withEnv(scanCodeEnv) {
40+                 def  pipelineCLIArgs =  generatePipelineArgs(settings. pipelines)
41+                 def  inputUrlCLIArgs =  generateInputUrlArgs(settings. inputUrls)
42+                 
43+                 sh """ 
44+                     scanpipe create-project ${ settings.projectName}   \\  
45+                     ${ pipelineCLIArgs}   \\  
46+                     ${ inputUrlCLIArgs}  
47+                 """  
48+                 
49+                 def  projectStatus =  sh(
50+                     script : " scanpipe status --project ${ settings.projectName} "  ,
51+                     returnStdout : true 
52+                 ). trim()
53+                 
54+                 def  workDirectory =  extractWorkDirectory(projectStatus)
55+                 env. PROJECT_WORK_DIRECTORY  =  workDirectory
56+             }
57+         }
58+         
59+         stage(' Copy Input Files'  ) {
60+             copyInputFiles(settings. inputsPath, env. PROJECT_WORK_DIRECTORY )
61+         }
62+         
63+         stage(' Run ScanCode Pipelines'  ) {
64+             withEnv(scanCodeEnv) {
65+                 sh " scanpipe execute --project ${ settings.projectName}   --no-color" 
66+             }
67+         }
68+         
69+         stage(' Generate Outputs'  ) {
70+             withEnv(scanCodeEnv) {
71+                 sh """ 
72+                     scanpipe output \\  
73+                     --project ${ settings.projectName}   \\  
74+                     --format ${ settings.outputFormats}  
75+                 """  
76+             }
77+         }
78+         
79+         stage(' Archive Outputs'  ) {
80+             archiveArtifacts(
81+                 artifacts : " ${ env.PROJECT_WORK_DIRECTORY}  /output/*"  ,
82+                 allowEmptyArchive : false ,
83+                 fingerprint : true 
84+             )
85+         }
86+         
87+         if  (settings. checkCompliance) {
88+             stage(' Check Compliance'  ) {
89+                 checkCompliance(
90+                     settings. projectName,
91+                     settings. complianceFailLevel,
92+                     settings. complianceFailOnVulnerabilities,
93+                     scanCodeEnv
94+                 )
95+             }
96+         }
97+         
98+         echo " ScanCode.io pipeline completed successfully" 
99+         
100+     } catch  (Exception  e) {
101+         error " ScanCode.io pipeline failed: ${ e.getMessage()} " 
102+     }
103+ }
104+ 
105+ def  setupPython (pythonVersion ) {
106+     echo " Setting up Python ${ pythonVersion} " 
107+ 
108+     sh """ 
109+         sudo apt-get update 
110+ 
111+         sudo apt-get install -y python${ pythonVersion}   python${ pythonVersion}  -pip python${ pythonVersion}  -venv 
112+ 
113+         sudo ln -sf /usr/bin/python${ pythonVersion}   /usr/bin/python3 
114+         sudo ln -sf /usr/bin/pip${ pythonVersion}   /usr/bin/pip3 
115+ 
116+         python3 --version 
117+         pip3 --version 
118+     """  
119+ }
120+ 
121+ def  setupPostgreSQL (scanCodeEnv ) {
122+     echo " Setting up PostgreSQL" 
123+     
124+     withEnv(scanCodeEnv) {
125+         sh """ 
126+ 
127+             sudo apt-get install -y postgresql postgresql-contrib 
128+             sudo systemctl start postgresql 
129+             sudo systemctl enable postgresql 
130+              
131+             sudo -u postgres createuser --no-createrole --no-superuser --login --inherit --createdb \$ SCANCODEIO_DB_USER || true 
132+             sudo -u postgres psql -c "ALTER USER \$ SCANCODEIO_DB_USER WITH encrypted password '\$ SCANCODEIO_DB_PASSWORD'" 
133+             sudo -u postgres createdb --owner=\$ SCANCODEIO_DB_USER --encoding=UTF-8 \$ SCANCODEIO_DB_NAME || true 
134+         """  
135+     }
136+ }
137+ 
138+ def  installScanCodeIO (branch ) {
139+     echo " Installing ScanCode.io" 
140+     
141+     if  (branch) {
142+         echo " Installing ScanCode.io from branch: ${ branch} " 
143+         sh " pip3 install git+https://github.com/aboutcode-org/scancode.io.git@${ branch} " 
144+     } else  {
145+         echo " Installing latest ScanCode.io release from PyPI" 
146+         sh " pip3 install --upgrade scancodeio" 
147+     }
148+ }
149+ 
150+ def  generatePipelineArgs (pipelines ) {
151+     def  pipelineList =  pipelines. split(' ,'  )
152+     def  args =  " " 
153+     
154+     pipelineList. each { pipeline  -> 
155+         args + =  "  --pipeline ${ pipeline.trim()} " 
156+     }
157+     
158+     return  args
159+ }
160+ 
161+ def  generateInputUrlArgs (inputUrls ) {
162+     if  (! inputUrls ||  inputUrls. trim(). isEmpty()) {
163+         return  " " 
164+     }
165+     
166+     def  urlList =  inputUrls. split(/ \s +/  )
167+     def  args =  " " 
168+     
169+     urlList. each { url  -> 
170+         if  (url. trim()) {
171+             args + =  "  --input-url ${ url.trim()} " 
172+         }
173+     }
174+     
175+     return  args
176+ }
177+ 
178+ def  extractWorkDirectory (projectStatus ) {
179+     def  matcher =  projectStatus =~  / Work directory:\s *([^\n ]+)/ 
180+     if  (matcher) {
181+         return  matcher[0 ][1 ]. trim()
182+     }
183+     error " Could not extract work directory from project status" 
184+ }
185+ 
186+ def  copyInputFiles (inputsPath , workDirectory ) {
187+     echo " Copying input files" 
188+     
189+     if  (fileExists(inputsPath)) {
190+         sh """ 
191+             mkdir -p ${ workDirectory}  /input/ 
192+             cp -r ${ inputsPath}  /* ${ workDirectory}  /input/ || true 
193+         """  
194+     } else  {
195+         echo " Input path ${ inputsPath}   does not exist, skipping file copy" 
196+     }
197+ }
198+ 
199+ def  checkCompliance (projectName , failLevel , failOnVulnerabilities , scanCodeEnv ) {
200+     echo " Checking compliance" 
201+     
202+     withEnv(scanCodeEnv) {
203+         def  cmd =  " scanpipe check-compliance --project ${ projectName}   --fail-level ${ failLevel} " 
204+         
205+         if  (failOnVulnerabilities) {
206+             cmd + =  "  --fail-on-vulnerabilities" 
207+         }
208+         
209+         try  {
210+             sh cmd
211+             echo " Compliance check passed" 
212+         } catch  (Exception  e) {
213+             error " Compliance check failed: ${ e.getMessage()} " 
214+         }
215+     }
216+ }
217+ 
218+ def  generateSecretKey () {
219+     return  sh(
220+         script : ' openssl rand -base64 32'  ,
221+         returnStdout : true 
222+     ). trim()
223+ }
0 commit comments