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