Skip to content

Commit dadfed8

Browse files
committed
chore: add a script to update dependencies
1 parent f3868e6 commit dadfed8

File tree

14 files changed

+361
-117
lines changed

14 files changed

+361
-117
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Upgrade template dependencies
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * 1' # Every Monday at midnight UTC
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
upgrade-template-deps:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
19+
20+
- name: Setup
21+
uses: ./.github/actions/setup
22+
23+
- name: Run upgrade script
24+
run: node scripts/upgrade-template-deps.mts
25+
26+
- name: Create or update pull request
27+
run: |
28+
if [ -z "$(git status --porcelain)" ]; then
29+
echo "No changes to commit."
30+
exit 0
31+
fi
32+
33+
git config user.name "github-actions[bot]"
34+
git config user.email "github-actions[bot]@users.noreply.github.com"
35+
36+
branch="upgrade-template-deps"
37+
38+
git checkout -B "$branch"
39+
git add -A
40+
git commit -m "chore: upgrade template dependencies"
41+
git push -u origin "$branch" --force
42+
43+
existing_pr=$(gh pr list --head "$branch" --json number --jq '.[0].number')
44+
45+
if [ -n "$existing_pr" ]; then
46+
echo "Updated existing PR #$existing_pr"
47+
else
48+
gh pr create \
49+
--title "chore: upgrade template dependencies" \
50+
--body "Automated upgrade of template dependencies via \`scripts/upgrade-template-deps.mts\`." \
51+
--label "dependencies"
52+
fi
53+
env:
54+
GH_TOKEN: ${{ github.token }}

eslint.config.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineConfig, globalIgnores } from 'eslint/config';
22
import { recommended, vitest, typechecked } from 'eslint-config-satya164';
3+
import globals from 'globals';
34

45
export default defineConfig(
56
recommended,
@@ -24,6 +25,13 @@ export default defineConfig(
2425
},
2526
},
2627

28+
{
29+
files: ['scripts/**'],
30+
languageOptions: {
31+
globals: globals.node,
32+
},
33+
},
34+
2735
globalIgnores([
2836
'**/.next/',
2937
'**/.expo/',

packages/create-react-native-library/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"github-username": "^6.0.0",
4949
"kleur": "^4.1.4",
5050
"ora": "^5.4.1",
51-
"pigment": "^0.3.11",
51+
"pigment": "^0.4.0",
5252
"validate-npm-package-name": "^4.0.0"
5353
},
5454
"devDependencies": {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const FALLBACK_BOB_VERSION = '0.40.13';
22
export const FALLBACK_NITRO_MODULES_VERSION = '0.29.8';
3+
export const SUPPORTED_MONOREPO_CONFIG_VERSION = '0.3.3';
34
export const SUPPORTED_REACT_NATIVE_VERSION = '0.83.0';

packages/create-react-native-library/src/exampleApp/generateExampleApp.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import dedent from 'dedent';
12
import fs from 'fs-extra';
23
import getLatestVersion from 'get-latest-version';
34
import https from 'https';
45
import path from 'path';
6+
import { SUPPORTED_MONOREPO_CONFIG_VERSION } from '../constants';
57
import type { TemplateConfiguration } from '../template';
68
import sortObjectKeys from '../utils/sortObjectKeys';
79
import { spawn } from '../utils/spawn';
8-
import dedent from 'dedent';
910

1011
const FILES_TO_DELETE = [
1112
'__tests__',
@@ -216,7 +217,7 @@ export default async function generateExampleApp({
216217

217218
const PACKAGES_TO_ADD_DEV = {
218219
'react-native-builder-bob': `^${config.versions.bob}`,
219-
'react-native-monorepo-config': `^0.3.3`,
220+
'react-native-monorepo-config': `^${SUPPORTED_MONOREPO_CONFIG_VERSION}`,
220221
};
221222

222223
if (

packages/create-react-native-library/src/template.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ export async function applyTemplate(
260260
const files = await fs.readdir(source);
261261

262262
for (const f of files) {
263+
if (f.startsWith('~')) {
264+
continue;
265+
}
266+
263267
let name;
264268

265269
try {

packages/create-react-native-library/src/utils/configureTools.ts

Lines changed: 34 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import fs from 'fs-extra';
22
import path from 'node:path';
33
import { applyTemplate, type TemplateConfiguration } from '../template';
44
import sortObjectKeys from './sortObjectKeys';
5-
import { SUPPORTED_REACT_NATIVE_VERSION } from '../constants';
65

76
type Tool = {
87
name: string;
98
description: string;
10-
package: Record<string, unknown>;
119
condition?: (config: TemplateConfiguration) => boolean;
1210
};
1311

@@ -21,109 +19,26 @@ type Options = {
2119
const ESLINT = {
2220
name: 'ESLint with Prettier',
2321
description: 'Lint and format code',
24-
package: {
25-
scripts: {
26-
lint: 'eslint "**/*.{js,ts,tsx}"',
27-
},
28-
prettier: {
29-
quoteProps: 'consistent',
30-
singleQuote: true,
31-
tabWidth: 2,
32-
trailingComma: 'es5',
33-
useTabs: false,
34-
},
35-
devDependencies: {
36-
'@eslint/compat': '^1.3.2',
37-
'@eslint/eslintrc': '^3.3.1',
38-
'@eslint/js': '^9.35.0',
39-
'@react-native/eslint-config': SUPPORTED_REACT_NATIVE_VERSION,
40-
'eslint-config-prettier': '^10.1.8',
41-
'eslint-plugin-prettier': '^5.5.4',
42-
'eslint': '^9.35.0',
43-
'prettier': '^2.8.8',
44-
},
45-
},
4622
};
4723

4824
const LEFTHOOK = {
4925
name: 'Lefthook with Commitlint',
5026
description: 'Manage Git hooks and lint commit messages',
51-
package: {
52-
commitlint: {
53-
extends: ['@commitlint/config-conventional'],
54-
},
55-
devDependencies: {
56-
'@commitlint/config-conventional': '^19.8.1',
57-
'commitlint': '^19.8.1',
58-
'lefthook': '^2.0.3',
59-
},
60-
},
6127
};
6228

6329
const RELEASE_IT = {
6430
name: 'Release It',
6531
description: 'Automate versioning and package publishing tasks',
66-
package: {
67-
'scripts': {
68-
release: 'release-it --only-version',
69-
},
70-
'release-it': {
71-
git: {
72-
// eslint-disable-next-line no-template-curly-in-string
73-
commitMessage: 'chore: release ${version}',
74-
// eslint-disable-next-line no-template-curly-in-string
75-
tagName: 'v${version}',
76-
},
77-
npm: {
78-
publish: true,
79-
},
80-
github: {
81-
release: true,
82-
},
83-
plugins: {
84-
'@release-it/conventional-changelog': {
85-
preset: {
86-
name: 'angular',
87-
},
88-
},
89-
},
90-
},
91-
'devDependencies': {
92-
'release-it': '^19.0.4',
93-
'@release-it/conventional-changelog': '^10.0.1',
94-
},
95-
},
9632
};
9733

9834
const JEST = {
9935
name: 'Jest',
10036
description: 'Test JavaScript and TypeScript code',
101-
package: {
102-
scripts: {
103-
test: 'jest',
104-
},
105-
jest: {
106-
preset: 'react-native',
107-
modulePathIgnorePatterns: [
108-
'<rootDir>/example/node_modules',
109-
'<rootDir>/lib/',
110-
],
111-
},
112-
devDependencies: {
113-
'@types/jest': '^29.5.14',
114-
'jest': '^29.7.0',
115-
},
116-
},
11737
};
11838

11939
const TURBOREPO = {
12040
name: 'Turborepo',
12141
description: 'Cache build outputs on CI',
122-
package: {
123-
devDependencies: {
124-
turbo: '^2.5.6',
125-
},
126-
},
12742
};
12843

12944
export const AVAILABLE_TOOLS = {
@@ -168,39 +83,49 @@ export async function configureTools({
16883
continue;
16984
}
17085

171-
const files = path.resolve(__dirname, `../../templates/tools/${key}`);
86+
const toolDir = path.resolve(__dirname, `../../templates/tools/${key}`);
17287

173-
if (fs.existsSync(files)) {
174-
await applyTemplate(config, files, root);
88+
if (fs.existsSync(toolDir)) {
89+
await applyTemplate(config, toolDir, root);
17590
}
17691

177-
for (const [key, value] of Object.entries(tool.package)) {
178-
if (
179-
typeof value === 'object' &&
180-
value !== null &&
181-
!Array.isArray(value)
182-
) {
183-
if (typeof packageJson[key] === 'object' || packageJson[key] == null) {
184-
packageJson[key] = {
185-
...packageJson[key],
186-
...value,
187-
};
92+
const pkgPath = path.join(toolDir, '~package.json');
18893

94+
if (fs.existsSync(pkgPath)) {
95+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
96+
const toolPkg = (await fs.readJson(pkgPath)) as Record<string, unknown>;
97+
98+
for (const [field, value] of Object.entries(toolPkg)) {
99+
if (
100+
typeof value === 'object' &&
101+
value !== null &&
102+
!Array.isArray(value)
103+
) {
189104
if (
190-
key === 'dependencies' ||
191-
key === 'devDependencies' ||
192-
key === 'peerDependencies'
105+
typeof packageJson[field] === 'object' ||
106+
packageJson[field] == null
193107
) {
194-
// @ts-expect-error: We know they are objects here
195-
packageJson[key] = sortObjectKeys(packageJson[key]);
108+
packageJson[field] = {
109+
...packageJson[field],
110+
...value,
111+
};
112+
113+
if (
114+
field === 'dependencies' ||
115+
field === 'devDependencies' ||
116+
field === 'peerDependencies'
117+
) {
118+
// @ts-expect-error: We know they are objects here
119+
packageJson[field] = sortObjectKeys(packageJson[field]);
120+
}
121+
} else {
122+
throw new Error(
123+
`Cannot merge '${field}' field because it is not an object (got '${String(packageJson[field])}').`
124+
);
196125
}
197126
} else {
198-
throw new Error(
199-
`Cannot merge '${key}' field because it is not an object (got '${String(packageJson[key])}').`
200-
);
127+
packageJson[field] = value;
201128
}
202-
} else {
203-
packageJson[key] = value;
204129
}
205130
}
206131
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"scripts": {
3+
"lint": "eslint \"**/*.{js,ts,tsx}\""
4+
},
5+
"prettier": {
6+
"quoteProps": "consistent",
7+
"singleQuote": true,
8+
"tabWidth": 2,
9+
"trailingComma": "es5",
10+
"useTabs": false
11+
},
12+
"devDependencies": {
13+
"@eslint/compat": "^1.3.2",
14+
"@eslint/eslintrc": "^3.3.1",
15+
"@eslint/js": "^9.35.0",
16+
"@react-native/eslint-config": "0.83.0",
17+
"eslint": "^9.35.0",
18+
"eslint-config-prettier": "^10.1.8",
19+
"eslint-plugin-prettier": "^5.5.4",
20+
"prettier": "^2.8.8"
21+
}
22+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"scripts": {
3+
"test": "jest"
4+
},
5+
"jest": {
6+
"preset": "react-native",
7+
"modulePathIgnorePatterns": [
8+
"<rootDir>/example/node_modules",
9+
"<rootDir>/lib/"
10+
]
11+
},
12+
"devDependencies": {
13+
"@types/jest": "^29.5.14",
14+
"jest": "^29.7.0"
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"commitlint": {
3+
"extends": ["@commitlint/config-conventional"]
4+
},
5+
"devDependencies": {
6+
"@commitlint/config-conventional": "^19.8.1",
7+
"commitlint": "^19.8.1",
8+
"lefthook": "^2.0.3"
9+
}
10+
}

0 commit comments

Comments
 (0)