Skip to content

Commit 9372bce

Browse files
authored
Merge pull request #2642 from RedisInsight/release/2.34.0
Release/2.34.0 to latest
2 parents 30b8339 + f473d79 commit 9372bce

File tree

315 files changed

+6104
-1789
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

315 files changed

+6104
-1789
lines changed

.circleci/config.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,10 @@ jobs:
555555
yarn --cwd redisinsight/api/ install --ignore-optional
556556
yarn --cwd redisinsight/ install --ignore-optional
557557
yarn install
558+
no_output_timeout: 15m
559+
- run:
560+
name: Install plugins dependencies and build plugins
561+
command: |
558562
yarn build:statics
559563
no_output_timeout: 15m
560564
- run:
@@ -609,6 +613,7 @@ jobs:
609613
- release/RedisInsight*.snap
610614
- release/*-linux.yml
611615
- release/redisstack
616+
612617
macosx:
613618
macos:
614619
xcode: 14.2.0
@@ -823,6 +828,32 @@ jobs:
823828
- store_artifacts:
824829
path: docker-release
825830
destination: docker-release
831+
licenses-check:
832+
executor: linux-executor
833+
steps:
834+
- checkout
835+
- restore_cache:
836+
<<: *uiDepsCacheKey
837+
<<: *apiDepsCacheKey
838+
- run:
839+
name: Run install all dependencies
840+
command: |
841+
yarn install
842+
yarn --cwd redisinsight/api install
843+
yarn --cwd tests/e2e install
844+
# Install plugins dependencies
845+
export pluginsOnlyInstall=1
846+
yarn build:statics
847+
- run:
848+
name: Generate licenses csv files and send csv data to google sheet
849+
command: |
850+
npm i -g license-checker
851+
852+
echo "$GOOGLE_ACCOUNT_SERVICE_KEY_BASE64" | base64 -id > gasKey.json
853+
SPREADSHEET_ID=$GOOGLE_SPREADSHEET_DEPENDENCIES_ID node .circleci/deps-licenses-report.js
854+
- store_artifacts:
855+
path: licenses
856+
destination: licenses
826857

827858
# Release jobs
828859
store-build-artifacts:
@@ -1169,6 +1200,7 @@ workflows:
11691200
- Build app - Linux (dev)
11701201
- Build app - MacOS (dev)
11711202
- Build app - Windows (dev)
1203+
11721204
# Main workflow for release/* and latest branches only
11731205
release:
11741206
jobs:
@@ -1244,6 +1276,7 @@ workflows:
12441276
- Build app - Linux (stage)
12451277
- Build app - MacOS (stage)
12461278
- Build app - Windows (stage)
1279+
12471280
# Needs approval from QA team that build was tested before merging to latest
12481281
- qa-approve:
12491282
name: Approved by QA team
@@ -1444,3 +1477,16 @@ workflows:
14441477
# report: true
14451478
# requires:
14461479
# - Build app - Windows (stage)
1480+
1481+
weekly:
1482+
triggers:
1483+
- schedule:
1484+
cron: '0 0 * * 1'
1485+
filters:
1486+
branches:
1487+
only:
1488+
- main
1489+
jobs:
1490+
# Process all licenses
1491+
- licenses-check:
1492+
name: Process licenses of packages

.circleci/deps-licenses-report.js

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

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ main.js.map
5858
vendor
5959
redisinsight/main.js.LICENSE.txt
6060
redisinsight/main.prod.js.LICENSE.txt
61+
licenses
6162

6263

6364
# E2E tests report

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ Alternatively you can also build from source. See our wiki for instructions.
4949

5050
* [How to build](https://github.com/RedisInsight/RedisInsight/wiki/How-to-build-and-contribute)
5151

52+
## How to debug
53+
If you have any issues occurring in RedisInsight, you can follow the steps below to get more information about the errors and find their root cause.
54+
55+
* [How to debug](https://github.com/RedisInsight/RedisInsight/wiki/How-to-debug)
56+
5257
## Feedback
5358

5459
* Request a new [feature](https://github.com/RedisInsight/RedisInsight/issues/new?assignees=&labels=&template=feature_request.md&title=%5BFeature+Request%5D%3A)

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"start:web:public": "cross-env PUBLIC_DEV=true NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./configs/webpack.config.web.dev.ts",
4343
"test": "jest ./redisinsight/ui -w 1",
4444
"test:watch": "jest ./redisinsight/ui --watch -w 1",
45-
"test:cov": "jest ./redisinsight/ui --coverage -w 1",
45+
"test:cov": "jest ./redisinsight/ui --coverage --runInBand",
4646
"test:cov:unit": "jest ./redisinsight/ui --group=-component --coverage -w 1",
4747
"test:cov:component": "jest ./redisinsight/ui --group=component --coverage -w 1",
4848
"type-check:ui": "tsc --project redisinsight/ui --noEmit"
@@ -160,6 +160,8 @@
160160
"cross-env": "^7.0.2",
161161
"css-loader": "^5.0.1",
162162
"css-minimizer-webpack-plugin": "^2.0.0",
163+
"csv-parser": "^3.0.0",
164+
"csv-stringify": "^6.4.0",
163165
"electron": "25.1.1",
164166
"electron-builder": "^23.6.0",
165167
"electron-builder-notarize": "^1.5.1",
@@ -179,6 +181,8 @@
179181
"eslint-plugin-react-hooks": "^4.0.8",
180182
"eslint-plugin-sonarjs": "^0.10.0",
181183
"file-loader": "^6.0.0",
184+
"google-auth-library": "^9.0.0",
185+
"googleapis": "^125.0.0",
182186
"html-webpack-plugin": "^5.5.0",
183187
"husky": "^4.2.5",
184188
"identity-obj-proxy": "^3.0.0",
@@ -187,6 +191,7 @@
187191
"jest": "^27.5.1",
188192
"jest-runner-groups": "^2.2.0",
189193
"jest-when": "^3.2.1",
194+
"license-checker": "^25.0.1",
190195
"lint-staged": "^10.2.11",
191196
"mini-css-extract-plugin": "2.7.2",
192197
"moment": "^2.29.3",

0 commit comments

Comments
 (0)