Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add fetch-based checks to CI for new data entries #1223

Merged
merged 4 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/test-and-validate.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: Test and Validate

on: [push, pull_request]
on:
push:
branches: [main]
pull_request:
paths:
- react-native-libraries.json

jobs:
test:
Expand All @@ -19,3 +24,7 @@ jobs:
run: yarn data:validate
- name: Test react-native-libraries.json
run: yarn data:test
- name: Check new entries in react-native-libraries.json
run: yarn ci:validate
env:
CI_CHECKS_TOKEN: ${{ secrets.CI_CHECKS_TOKEN }}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"libraries:recalculate": "node --no-warnings scripts/recalculate-popularity.js",
"libraries:format": "prettier --write react-native-libraries.json",
"libraries:check": "node --no-warnings scripts/check-resources.js",
"ci:validate": "node --no-warnings scripts/validate-new-entries.js",
"precommit": "simple-git-hooks && lint-staged"
},
"dependencies": {
Expand Down
14 changes: 6 additions & 8 deletions scripts/build-and-score-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { calculateDirectoryScore, calculatePopularityScore } from './calculate-s
import { fetchGithubData, fetchGithubRateLimit, loadGitHubLicenses } from './fetch-github-data.js';
import { fetchNpmData, fetchNpmDataBulk } from './fetch-npm-data.js';
import fetchReadmeImages from './fetch-readme-images.js';
import { fillNpmName, sleep } from './helpers.js';
import { fillNpmName, hasMismatchedPackageData, sleep } from './helpers.js';
import debugGithubRepos from '../debug-github-repos.json' assert { type: 'json' };
import githubRepos from '../react-native-libraries.json' assert { type: 'json' };
import { isLaterThan, TimeRange } from '../util/datetime.js';
Expand Down Expand Up @@ -45,9 +45,7 @@ const buildAndScoreData = async () => {

// Detect mismatched package and package.json content
data.forEach(project => {
if (
(project.npmPkg ?? project.githubUrl.split('/').pop()).toLowerCase() !== project.github.name
) {
if (hasMismatchedPackageData(project)) {
mismatchedRepos.push(project);
}
});
Expand Down Expand Up @@ -210,7 +208,7 @@ const buildAndScoreData = async () => {
}
};

async function fetchGithubDataThrottled({ data, chunkSize, staggerMs }) {
export async function fetchGithubDataThrottled({ data, chunkSize, staggerMs }) {
let results = [];
const chunks = chunk(data, chunkSize);
for (const c of chunks) {
Expand All @@ -233,8 +231,8 @@ async function fetchGithubDataThrottled({ data, chunkSize, staggerMs }) {
return results;
}

function getDataForFetch() {
if (wantedPackageName) {
function getDataForFetch(wantedPackage) {
if (wantedPackage) {
const match = DATASET.find(
entry =>
entry?.npmPkg === wantedPackageName || entry.githubUrl.endsWith(`/${wantedPackageName}`)
Expand All @@ -249,7 +247,7 @@ function getDataForFetch() {
}

async function loadRepositoryDataAsync() {
const data = getDataForFetch();
const data = getDataForFetch(wantedPackageName);

let githubResultsFileExists = false;
try {
Expand Down
6 changes: 4 additions & 2 deletions scripts/fetch-github-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ config();

const GRAPHQL_API = 'https://api.github.com/graphql';

const AUTHORIZATION = `bearer ${process.env.GITHUB_TOKEN}`;
const AUTHORIZATION = `bearer ${process.env.GITHUB_TOKEN ?? process.env.CI_CHECKS_TOKEN}`;

const licenses = {};

Expand Down Expand Up @@ -87,7 +87,7 @@ const parseUrl = url => {

export const fetchGithubData = async (data, retries = 2) => {
if (retries < 0) {
console.warn(`[GH] ERROR fetching ${data.githubUrl} - OUT OF RETRIES`);
console.error(`[GH] ERROR fetching ${data.githubUrl} - OUT OF RETRIES`);
return data;
}
try {
Expand Down Expand Up @@ -151,6 +151,7 @@ const createRepoDataWithResponse = (json, monorepo) => {

json.newArchitecture = Boolean(packageJson.codegenConfig);
json.name = packageJson.name;
json.isPackagePrivate = packageJson.private ?? false;

if (monorepo) {
json.homepageUrl = packageJson.homepage;
Expand Down Expand Up @@ -215,6 +216,7 @@ const createRepoDataWithResponse = (json, monorepo) => {
},
name: json.name,
fullName: json.nameWithOwner,
isPrivate: json.isPackagePrivate,
description: json.description,
topics: json.topics,
license: json.licenseInfo,
Expand Down
6 changes: 6 additions & 0 deletions scripts/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ export function processTopics(topics) {
)
.filter(topic => topic?.length);
}

export function hasMismatchedPackageData(project) {
return (
(project.npmPkg ?? project.githubUrl.split('/').at(-1)).toLowerCase() !== project.github?.name
);
}
80 changes: 80 additions & 0 deletions scripts/validate-new-entries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import fetch from 'cross-fetch';
import differenceWith from 'lodash/differenceWith.js';
import isEqual from 'lodash/isEqual.js';

import { fetchGithubData } from './fetch-github-data.js';
import { fetchNpmData } from './fetch-npm-data.js';
import { fillNpmName, hasMismatchedPackageData } from './helpers.js';
import libraries from '../react-native-libraries.json' assert { type: 'json' };

async function makeBaseFileQuery() {
const result = await fetch(
'https://raw.githubusercontent.com/react-native-community/directory/main/react-native-libraries.json'
);
return await result.json();
}

const mainData = await makeBaseFileQuery();

if (libraries.length !== mainData.length) {
console.log('πŸ”οΈ Detected changes in data entries, checking!');

const modifiedEntries = differenceWith(libraries, mainData, isEqual);

const checkResults = await Promise.all(
modifiedEntries.map(async entry => {
const entryWithNpmData = await fetchNpmData(fillNpmName(entry));

if (!entryWithNpmData.npm) {
console.error(
`Unable to fetch npm package data for ${entryWithNpmData.npmPkg} package! Please make sure that the package exist in npm registry.`
);
return false;
}

const entryWithGitHubData = await fetchGithubData(entryWithNpmData);

if (!entryWithGitHubData.github) {
console.error(`Unable to fetch data from ${entryWithGitHubData.githubUrl} repository!`);
return false;
}

if (!entryWithGitHubData.github.isPackagePrivate) {
console.error(
`Extracted 'package.json' from ${entryWithGitHubData.githubUrl} is marked as private! You might be linking to the monorepo/workspace root, instead of wanted package directory.`
);
return false;
}

if (!entryWithGitHubData.github.name) {
console.error(
`Extracted 'package.json' from ${entryWithGitHubData.githubUrl} does not contains package name! You might be linking to the monorepo/workspace root, instead of wanted package directory.`
);
return false;
}

if (hasMismatchedPackageData(entryWithGitHubData)) {
console.error(
`Package name extracted from 'package.json' at given GitHub repository URL differs with package name in the directory data!`
);
console.error(
`- Supplied package name: ${entryWithGitHubData.npmPkg ?? entryWithGitHubData.githubUrl.split('/').at(-1)}`
);
console.error(
`- Extracted package name: ${entryWithGitHubData.github.name ?? entryWithGitHubData.github.fullName.split('/').at(-1)}`
);

return false;
}
return true;
})
);

if (checkResults.filter(result => !result).length > 0) {
console.error('\n❌ There were errors spotted during new entries check!');
process.exit(1);
}
console.log('βœ… All checks have passed!');
}

console.log('βœ… There was no data changes detected!');
15 changes: 8 additions & 7 deletions types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ export type Library = {
newArchitectureNote?: string;
alternatives?: string[];
github: {
name: string;
isPackagePrivate: boolean;
fullName: string;
description: string;
topics?: string[];
hasTypes?: boolean;
newArchitecture?: boolean;
isArchived?: boolean;
urls: {
repo: string;
clone: string;
Expand All @@ -72,10 +80,6 @@ export type Library = {
stars: number;
forks: number;
};
name: string;
fullName: string;
description: string;
topics?: string[];
license: {
key: string;
name: string;
Expand All @@ -90,9 +94,6 @@ export type Library = {
publishedAt: Date | string;
isPrerelease: boolean;
};
hasTypes?: boolean;
newArchitecture?: boolean;
isArchived?: boolean;
};
npm?: {
downloads?: number;
Expand Down