Skip to content

Commit 9f26e9e

Browse files
authored
Merge pull request #178 from RedisInsight/main
fixes
2 parents 3a8180c + bb2de5e commit 9f26e9e

File tree

33 files changed

+541
-82
lines changed

33 files changed

+541
-82
lines changed

.circleci/config.yml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,18 @@ jobs:
182182
- run:
183183
name: Build .vsix package
184184
command: |
185-
packagePath=./release/redis-for-vscode-extension-linux-x64.vsix
185+
envFile=".env"
186+
packagePath="./release/redis-for-vscode-extension-linux-x64.vsix"
186187
yarn download:backend
187188
188189
if [ << parameters.env >> == 'prod' ]; then
190+
echo "RI_SEGMENT_WRITE_KEY='$RI_SEGMENT_WRITE_KEY'" >> $envFile
189191
yarn package:prod --out ${packagePath}
190192
exit 0;
191193
fi
192194
195+
echo "RI_SEGMENT_WRITE_KEY='$RI_SEGMENT_WRITE_KEY_STAGE'" >> $envFile
196+
sed -i "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" $envFile
193197
yarn package:stage --out ${packagePath}
194198
- persist_to_workspace:
195199
root: .
@@ -329,6 +333,27 @@ jobs:
329333
330334
aws s3 cp release/ s3://${AWS_BUCKET_NAME}/private/vscode/${applicationVersion} --recursive
331335
336+
licenses-check:
337+
executor: linux-executor
338+
steps:
339+
- checkout
340+
- restore_cache:
341+
<<: *uiDepsCacheKey
342+
- run:
343+
name: Run install all dependencies
344+
command: |
345+
yarn install
346+
yarn --cwd tests/e2e install
347+
- run:
348+
name: Generate licenses csv files and send csv data to google sheet
349+
command: |
350+
npm i -g license-checker
351+
352+
echo "$GOOGLE_ACCOUNT_SERVICE_KEY_BASE64" | base64 -id > gasKey.json
353+
SPREADSHEET_ID=$GOOGLE_SPREADSHEET_DEPENDENCIES_ID node .circleci/deps-licenses-report.js
354+
- store_artifacts:
355+
path: licenses
356+
destination: licenses
332357

333358
# Orchestrate jobs using workflows
334359
# See: https://circleci.com/docs/configuration-reference/#workflows
@@ -539,3 +564,16 @@ workflows:
539564
# - Approve Publish Release (prod)
540565
# <<: *prodFilter # double check for "latest"
541566

567+
weekly:
568+
triggers:
569+
- schedule:
570+
cron: '0 0 * * 1'
571+
filters:
572+
branches:
573+
only:
574+
- main
575+
jobs:
576+
# Process all licenses
577+
- licenses-check:
578+
name: Process licenses of packages
579+

.circleci/deps-licenses-report.js

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
const fs = require('fs');
2+
const { join } = require('path');
3+
const { last, set } = require('lodash');
4+
const { google } = require('googleapis');
5+
const { exec } = require('child_process');
6+
const csvParser = require('csv-parser');
7+
const { stringify } = require('csv-stringify');
8+
9+
const licenseFolderName = 'licenses';
10+
const spreadsheetId = process.env.SPREADSHEET_ID;
11+
const summaryFilePath = `./${licenseFolderName}/summary.csv`;
12+
const allData = [];
13+
let csvFiles = [];
14+
15+
// Main function
16+
async function main() {
17+
const folderPath = './';
18+
const packageJsons = findPackageJsonFiles(folderPath); // Find all package.json files in the given folder
19+
20+
console.log('All package.jsons was found:', packageJsons);
21+
22+
// Create the folder if it doesn't exist
23+
if (!fs.existsSync(licenseFolderName)) {
24+
fs.mkdirSync(licenseFolderName);
25+
}
26+
27+
try {
28+
await Promise.all(packageJsons.map(runLicenseCheck));
29+
console.log('All csv files was generated');
30+
await generateSummary()
31+
await sendLicensesToGoogleSheet()
32+
} catch (error) {
33+
console.error('An error occurred:', error);
34+
process.exit(1);
35+
}
36+
}
37+
38+
main();
39+
40+
// Function to find all package.json files in a given folder
41+
function findPackageJsonFiles(folderPath) {
42+
const packageJsonPaths = [];
43+
const packageJsonName = 'package.json';
44+
const excludeFolders = ['dist', 'node_modules', 'test-extensions'];
45+
46+
// Recursive function to search for package.json files
47+
function searchForPackageJson(currentPath) {
48+
const files = fs.readdirSync(currentPath);
49+
50+
for (const file of files) {
51+
const filePath = join(currentPath, file);
52+
const stats = fs.statSync(filePath);
53+
54+
if (stats.isDirectory() && !excludeFolders.includes(file)) {
55+
searchForPackageJson(filePath);
56+
} else if (file === packageJsonName) {
57+
packageJsonPaths.push(`./${filePath.slice(0, -packageJsonName.length - 1)}`);
58+
}
59+
}
60+
}
61+
62+
searchForPackageJson(folderPath);
63+
return packageJsonPaths;
64+
}
65+
66+
// Function to run license check for a given package.json file
67+
async function runLicenseCheck(path) {
68+
const name = last(path.split('/')) || 'vscode';
69+
70+
const COMMANDS = [
71+
`license-checker --start ${path} --csv --out ./${licenseFolderName}/${name}_prod.csv --production`,
72+
`license-checker --start ${path} --csv --out ./${licenseFolderName}/${name}_dev.csv --development`,
73+
]
74+
75+
return await Promise.all(COMMANDS.map((command) =>
76+
new Promise((resolve, reject) => {
77+
exec(command, (error, stdout, stderr) => {
78+
if (error) {
79+
console.error(`Failed command: ${command}, error:`, stderr);
80+
reject(error);
81+
}
82+
resolve();
83+
});
84+
})
85+
));
86+
}
87+
88+
async function sendLicensesToGoogleSheet() {
89+
try {
90+
const serviceAccountKey = JSON.parse(fs.readFileSync('./gasKey.json', 'utf-8'));
91+
92+
// Set up JWT client
93+
const jwtClient = new google.auth.JWT(
94+
serviceAccountKey.client_email,
95+
null,
96+
serviceAccountKey.private_key,
97+
['https://www.googleapis.com/auth/spreadsheets']
98+
);
99+
100+
const sheets = google.sheets('v4');
101+
102+
// Read all .csv files in the 'licenses' folder
103+
csvFiles.forEach((csvFile) => {
104+
// Extract sheet name from file name
105+
const sheetName = csvFile.replace('.csv', '').replaceAll('_', ' ');
106+
107+
const data = [];
108+
fs.createReadStream(`./${licenseFolderName}/${csvFile}`)
109+
.pipe(csvParser({ headers: false }))
110+
.on('data', (row) => {
111+
data.push(Object.values(row));
112+
})
113+
.on('end', async () => {
114+
const resource = { values: data };
115+
116+
try {
117+
const response = await sheets.spreadsheets.get({
118+
auth: jwtClient,
119+
spreadsheetId,
120+
});
121+
122+
const sheet = response.data.sheets.find((sheet) => sheet.properties.title === sheetName);
123+
if (sheet) {
124+
// Clear contents of the sheet starting from cell A2
125+
await sheets.spreadsheets.values.clear({
126+
auth: jwtClient,
127+
spreadsheetId,
128+
range: `${sheetName}!A1:Z`, // Assuming Z is the last column
129+
});
130+
} else {
131+
// Create the sheet if it doesn't exist
132+
await sheets.spreadsheets.batchUpdate({
133+
auth: jwtClient,
134+
spreadsheetId,
135+
resource: set({}, 'requests[0].addSheet.properties.title', sheetName),
136+
});
137+
}
138+
} catch (error) {
139+
console.error(`Error checking/creating sheet for ${sheetName}:`, error);
140+
}
141+
142+
try {
143+
await sheets.spreadsheets.values.batchUpdate({
144+
auth: jwtClient,
145+
spreadsheetId,
146+
resource: {
147+
valueInputOption: 'RAW',
148+
data: [
149+
{
150+
range: `${sheetName}!A1`, // Use the sheet name as the range and start from A2
151+
majorDimension: 'ROWS',
152+
values: data,
153+
},
154+
],
155+
},
156+
});
157+
158+
console.log(`CSV data has been inserted into ${sheetName} sheet.`);
159+
} catch (err) {
160+
console.error(`Error inserting data for ${sheetName}:`, err);
161+
}
162+
});
163+
});
164+
} catch (error) {
165+
console.error('Error loading service account key:', error);
166+
}
167+
}
168+
169+
// Function to read and process each CSV file
170+
const processCSVFile = (file) => {
171+
return new Promise((resolve, reject) => {
172+
const parser = csvParser({ columns: true, trim: true });
173+
const input = fs.createReadStream(`./${licenseFolderName}/${file}`);
174+
175+
parser.on('data', (record) => {
176+
allData.push(record);
177+
});
178+
179+
parser.on('end', () => {
180+
resolve();
181+
});
182+
183+
parser.on('error', (err) => {
184+
reject(err);
185+
});
186+
187+
input.pipe(parser);
188+
});
189+
};
190+
191+
// Process and aggregate license data
192+
const processLicenseData = () => {
193+
const licenseCountMap = {};
194+
for (const record of allData) {
195+
const license = record.license;
196+
licenseCountMap[license] = (licenseCountMap[license] || 0) + 1;
197+
}
198+
return licenseCountMap;
199+
};
200+
201+
// Create summary CSV data
202+
const createSummaryData = (licenseCountMap) => {
203+
const summaryData = [['License', 'Count']];
204+
for (const license in licenseCountMap) {
205+
summaryData.push([license, licenseCountMap[license]]);
206+
}
207+
return summaryData;
208+
};
209+
210+
// Write summary CSV file
211+
const writeSummaryCSV = async (summaryData) => {
212+
try {
213+
const summaryCsvString = await stringifyPromise(summaryData);
214+
fs.writeFileSync(summaryFilePath, summaryCsvString);
215+
csvFiles.push(last(summaryFilePath.split('/')));
216+
console.log(`Summary CSV saved as ${summaryFilePath}`);
217+
} catch (err) {
218+
console.error(`Error: ${err}`);
219+
}
220+
};
221+
222+
// Stringify as a promise
223+
const stringifyPromise = (data) => {
224+
return new Promise((resolve, reject) => {
225+
stringify(data, (err, csvString) => {
226+
if (err) {
227+
reject(err);
228+
} else {
229+
resolve(csvString);
230+
}
231+
});
232+
});
233+
};
234+
235+
async function generateSummary() {
236+
csvFiles = fs.readdirSync(licenseFolderName).filter(file => file.endsWith('.csv')).sort();
237+
238+
for (const file of csvFiles) {
239+
try {
240+
await processCSVFile(file);
241+
} catch (err) {
242+
console.error(`Error processing ${file}: ${err}`);
243+
}
244+
}
245+
246+
const licenseCountMap = processLicenseData();
247+
const summaryData = createSummaryData(licenseCountMap);
248+
249+
await writeSummaryCSV(summaryData);
250+
}

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
NODE_ENV='production'
66
RI_BASE_APP_URL='http://localhost'
77
RI_APP_PORT=5541
8+
RI_APP_VERSION='0.0.1'
89
RI_APP_PREFIX='api'
910
RI_APP_FOLDER_NAME='.redis-for-vscode'
1011
RI_CDN_PATH='https://s3.amazonaws.com/redisinsight.download/public/releases/2.54.1/web-mini'

.vscodeignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ node_modules
2222
!node_modules/debug
2323
vite.config.mjs
2424
*.zip
25+
.eslintignore
26+
.env.stage
2527

2628
# test
2729
coverage

l10n/bundle.l10n.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
"Last Refresh": "Last Refresh",
1111
"- Welcome": "- Welcome",
1212
"About Redis for VS Code": "About Redis for VS Code",
13-
"Take your productivity to the next level when developing with Redis or Redis Stack! Use Redis for VS Code to visualize and optimize Redis data.": "Take your productivity to the next level when developing with Redis or Redis Stack! Use Redis for VS Code to visualize and optimize Redis data.",
14-
"A powerful desktop manager, Redis for VS Code provides an intuitive and efficient UI for Redis and Redis Stack and supports CLI interaction in a fully-featured desktop UI client.": "A powerful desktop manager, Redis for VS Code provides an intuitive and efficient UI for Redis and Redis Stack and supports CLI interaction in a fully-featured desktop UI client.",
13+
"Redis for VS Code provides an intuitive and efficient UI to visualize and optimize your Redis data.": "Redis for VS Code provides an intuitive and efficient UI to visualize and optimize your Redis data.",
1514
"Start": "Start",
1615
"Connect your database": "Connect your database",
1716
"Create new database": "Create new database",
@@ -53,6 +52,9 @@
5352
"Score": "Score",
5453
"Use CLI to edit the score": "Use CLI to edit the score",
5554
"Enter Score": "Enter Score",
55+
"This data type is not currently supported.": "This data type is not currently supported.",
56+
"We are constantly working to launch support for more data types. If you have any ideas or suggestions, please ": "We are constantly working to launch support for more data types. If you have any ideas or suggestions, please ",
57+
"contact us.": "contact us.",
5658
"Edit value": "Edit value",
5759
"Empty": "Empty",
5860
"loading...": "loading...",
@@ -100,11 +102,11 @@
100102
"TTL: No limit": "TTL: No limit",
101103
"Key name*": "Key name*",
102104
"Encrypted data": "Encrypted data",
103-
"RedisJSON module should be loaded to add this key. Find ": "RedisJSON module should be loaded to add this key. Find ",
104-
"more information": "more information",
105-
" about RedisJSON or create your ": " about RedisJSON or create your ",
106-
"free Redis database": "free Redis database",
107-
" with RedisJSON on Redis Cloud.": " with RedisJSON on Redis Cloud.",
105+
"This database does not support the JSON data structure. Learn more about JSON support ": "This database does not support the JSON data structure. Learn more about JSON support ",
106+
"here.": "here.",
107+
"You can also create a ": "You can also create a ",
108+
"free Redis Cloud database": "free Redis Cloud database",
109+
" with built-in JSON support.": " with built-in JSON support.",
108110
"If you remove the single {0}, the whole Key will be deleted.": "If you remove the single {0}, the whole Key will be deleted.",
109111
"Removing multiple elements is available for Redis databases v. 6.2 or later. Update your Redis database or create a new ": "Removing multiple elements is available for Redis databases v. 6.2 or later. Update your Redis database or create a new ",
110112
"free up-to-date": "free up-to-date",
@@ -313,4 +315,4 @@
313315
"Add": "Add",
314316
"Release Notes": "Release Notes",
315317
"Redis for VS Code extension updated to {0}.": "Redis for VS Code extension updated to {0}."
316-
}
318+
}

0 commit comments

Comments
 (0)