@rindrics/initrepo 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,11 +16,13 @@ jobs:
16
16
  with:
17
17
  token: ${{ secrets.PAT_FOR_TAGPR }}
18
18
 
19
- - name: Configure SSH signing
19
+ - name: Configure Git and SSH signing
20
20
  run: |
21
21
  mkdir -p ~/.ssh
22
22
  echo "${{ secrets.SSH_SIGNING_KEY }}" > ~/.ssh/signing_key
23
23
  chmod 600 ~/.ssh/signing_key
24
+ git config --global user.name "Rindrics"
25
+ git config --global user.email "${{ secrets.GIT_USER_EMAIL }}"
24
26
  git config --global gpg.format ssh
25
27
  git config --global user.signingkey ~/.ssh/signing_key
26
28
  git config --global commit.gpgsign true
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.3.1](https://github.com/Rindrics/initrepo/compare/v0.3.0...v0.3.1) - 2026-01-19
4
+ - feat: add renovate command by @Rindrics in https://github.com/Rindrics/initrepo/pull/38
5
+
6
+ ## [v0.3.0](https://github.com/Rindrics/initrepo/compare/v0.2.1...v0.3.0) - 2026-01-19
7
+ - ci: use renovate to use bun by @Rindrics in https://github.com/Rindrics/initrepo/pull/35
8
+ - feat: generate tagpr config by @Rindrics in https://github.com/Rindrics/initrepo/pull/37
9
+
3
10
  ## [v0.2.1](https://github.com/Rindrics/initrepo/compare/v0.2.0...v0.2.1) - 2026-01-19
4
11
  - docs: update README.md by @Rindrics in https://github.com/Rindrics/initrepo/pull/24
5
12
  - feat: add command setup-husky by @Rindrics in https://github.com/Rindrics/initrepo/pull/32
package/dist/cli.js CHANGED
@@ -4207,7 +4207,7 @@ var {
4207
4207
  // package.json
4208
4208
  var package_default = {
4209
4209
  name: "@rindrics/initrepo",
4210
- version: "0.2.1",
4210
+ version: "0.3.1",
4211
4211
  description: "setup GitHub repo with dev tools",
4212
4212
  type: "module",
4213
4213
  bin: {
@@ -4363,6 +4363,21 @@ bun run build
4363
4363
  exclude:
4364
4364
  labels:
4365
4365
  - tagpr
4366
+ `,
4367
+ "common/renovate.json5.ejs": `{
4368
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
4369
+ "extends": ["config:recommended"],
4370
+ "packageRules": [
4371
+ {
4372
+ "matchUpdateTypes": ["major", "minor", "patch"],
4373
+ "automerge": true
4374
+ }
4375
+ ],
4376
+ "lockFileMaintenance": {
4377
+ "enabled": true,
4378
+ "schedule": ["before 5am on monday"]
4379
+ }
4380
+ }
4366
4381
  `,
4367
4382
  "common/workflows/publish.yml.ejs": `name: Publish to npm
4368
4383
 
@@ -11641,6 +11656,175 @@ function registerSetupHuskyCommand(program2) {
11641
11656
  });
11642
11657
  }
11643
11658
 
11659
+ // src/commands/setup-renovate.ts
11660
+ import * as fs4 from "node:fs/promises";
11661
+ import * as path4 from "node:path";
11662
+ async function fileExists2(filePath) {
11663
+ try {
11664
+ await fs4.access(filePath);
11665
+ return true;
11666
+ } catch {
11667
+ return false;
11668
+ }
11669
+ }
11670
+ function generateRenovateSetup() {
11671
+ return [
11672
+ {
11673
+ path: "renovate.json5",
11674
+ content: loadTemplate("common/renovate.json5.ejs", {})
11675
+ }
11676
+ ];
11677
+ }
11678
+ async function writeFiles2(targetDir, files, force) {
11679
+ const written = [];
11680
+ const skipped = [];
11681
+ for (const file of files) {
11682
+ const filePath = path4.join(targetDir, file.path);
11683
+ const fileDir = path4.dirname(filePath);
11684
+ if (!force && await fileExists2(filePath)) {
11685
+ skipped.push(file.path);
11686
+ continue;
11687
+ }
11688
+ await fs4.mkdir(fileDir, { recursive: true });
11689
+ await fs4.writeFile(filePath, file.content, "utf-8");
11690
+ written.push(file.path);
11691
+ }
11692
+ return { written, skipped };
11693
+ }
11694
+ async function setupRenovate(options) {
11695
+ const targetDir = options.targetDir ?? process.cwd();
11696
+ const force = options.force ?? false;
11697
+ const packageJsonPath = path4.join(targetDir, "package.json");
11698
+ if (!await fileExists2(packageJsonPath)) {
11699
+ throw new Error("package.json not found. Are you in a project directory?");
11700
+ }
11701
+ console.log(`\uD83D\uDD27 Setting up Renovate configuration...
11702
+ `);
11703
+ const files = generateRenovateSetup();
11704
+ const { written, skipped } = await writeFiles2(targetDir, files, force);
11705
+ if (written.length > 0) {
11706
+ console.log("✅ Created files:");
11707
+ for (const file of written) {
11708
+ console.log(` ${file}`);
11709
+ }
11710
+ }
11711
+ if (skipped.length > 0) {
11712
+ console.log(`
11713
+ ⏭️ Skipped (already exist, use --force to overwrite):`);
11714
+ for (const file of skipped) {
11715
+ console.log(` ${file}`);
11716
+ }
11717
+ }
11718
+ console.log(`
11719
+ \uD83C\uDF89 Renovate setup complete!`);
11720
+ console.log(`
11721
+ \uD83D\uDCCB Next steps:`);
11722
+ console.log(" 1. Install Renovate GitHub App: https://github.com/apps/renovate");
11723
+ console.log(" 2. Grant access to this repository");
11724
+ }
11725
+ function registerSetupRenovateCommand(program2) {
11726
+ program2.command("setup-renovate").description("Set up Renovate configuration in an existing project").option("-t, --target-dir <path>", "Target directory (defaults to current directory)").option("-f, --force", "Overwrite existing files").action(async (opts) => {
11727
+ try {
11728
+ await setupRenovate({
11729
+ targetDir: opts.targetDir,
11730
+ force: opts.force
11731
+ });
11732
+ } catch (error) {
11733
+ console.error(`❌ Failed to setup Renovate: ${error instanceof Error ? error.message : String(error)}`);
11734
+ process.exit(1);
11735
+ }
11736
+ });
11737
+ }
11738
+
11739
+ // src/commands/setup-tagpr.ts
11740
+ import * as fs5 from "node:fs/promises";
11741
+ import * as path5 from "node:path";
11742
+ async function fileExists3(filePath) {
11743
+ try {
11744
+ await fs5.access(filePath);
11745
+ return true;
11746
+ } catch {
11747
+ return false;
11748
+ }
11749
+ }
11750
+ async function generateTagprSetup() {
11751
+ const actionVersions = await getLatestActionVersions();
11752
+ return [
11753
+ {
11754
+ path: ".tagpr",
11755
+ content: loadTemplate("typescript/.tagpr.ejs", {})
11756
+ },
11757
+ {
11758
+ path: ".github/workflows/tagpr.yml",
11759
+ content: loadTemplate("common/workflows/tagpr.yml.ejs", {
11760
+ isDevcode: false,
11761
+ actionVersions
11762
+ })
11763
+ }
11764
+ ];
11765
+ }
11766
+ async function writeFiles3(targetDir, files, force) {
11767
+ const written = [];
11768
+ const skipped = [];
11769
+ for (const file of files) {
11770
+ const filePath = path5.join(targetDir, file.path);
11771
+ const fileDir = path5.dirname(filePath);
11772
+ if (!force && await fileExists3(filePath)) {
11773
+ skipped.push(file.path);
11774
+ continue;
11775
+ }
11776
+ await fs5.mkdir(fileDir, { recursive: true });
11777
+ await fs5.writeFile(filePath, file.content, "utf-8");
11778
+ written.push(file.path);
11779
+ }
11780
+ return { written, skipped };
11781
+ }
11782
+ async function setupTagpr(options) {
11783
+ const targetDir = options.targetDir ?? process.cwd();
11784
+ const force = options.force ?? false;
11785
+ const packageJsonPath = path5.join(targetDir, "package.json");
11786
+ if (!await fileExists3(packageJsonPath)) {
11787
+ throw new Error("package.json not found. Are you in a project directory?");
11788
+ }
11789
+ console.log(`\uD83D\uDD27 Setting up tagpr configuration...
11790
+ `);
11791
+ const files = await generateTagprSetup();
11792
+ const { written, skipped } = await writeFiles3(targetDir, files, force);
11793
+ if (written.length > 0) {
11794
+ console.log("✅ Created files:");
11795
+ for (const file of written) {
11796
+ console.log(` ${file}`);
11797
+ }
11798
+ }
11799
+ if (skipped.length > 0) {
11800
+ console.log(`
11801
+ ⏭️ Skipped (already exist, use --force to overwrite):`);
11802
+ for (const file of skipped) {
11803
+ console.log(` ${file}`);
11804
+ }
11805
+ }
11806
+ console.log(`
11807
+ \uD83C\uDF89 Tagpr setup complete!`);
11808
+ console.log(`
11809
+ \uD83D\uDCCB Required secrets:`);
11810
+ console.log(" PAT_FOR_TAGPR - Personal Access Token with repo & workflow permissions");
11811
+ console.log(" SSH_SIGNING_KEY - SSH private key for commit signing");
11812
+ console.log(" GIT_USER_EMAIL - Email address for commits (optional)");
11813
+ }
11814
+ function registerSetupTagprCommand(program2) {
11815
+ program2.command("setup-tagpr").description("Set up tagpr configuration in an existing project").option("-t, --target-dir <path>", "Target directory (defaults to current directory)").option("-f, --force", "Overwrite existing files").action(async (opts) => {
11816
+ try {
11817
+ await setupTagpr({
11818
+ targetDir: opts.targetDir,
11819
+ force: opts.force
11820
+ });
11821
+ } catch (error) {
11822
+ console.error(`❌ Failed to setup tagpr: ${error instanceof Error ? error.message : String(error)}`);
11823
+ process.exit(1);
11824
+ }
11825
+ });
11826
+ }
11827
+
11644
11828
  // src/cli.ts
11645
11829
  var { version: VERSION17, name: NAME } = package_default;
11646
11830
  function createProgram() {
@@ -11649,6 +11833,8 @@ function createProgram() {
11649
11833
  registerInitCommand(program2);
11650
11834
  registerPrepareReleaseCommand(program2);
11651
11835
  registerSetupHuskyCommand(program2);
11836
+ registerSetupRenovateCommand(program2);
11837
+ registerSetupTagprCommand(program2);
11652
11838
  return program2;
11653
11839
  }
11654
11840
  if (__require.main == __require.module) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rindrics/initrepo",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "setup GitHub repo with dev tools",
5
5
  "type": "module",
6
6
  "bin": {
package/renovate.json5 ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": ["config:recommended"],
4
+ "packageRules": [
5
+ {
6
+ "matchUpdateTypes": ["major", "minor", "patch"],
7
+ "automerge": true
8
+ }
9
+ ],
10
+ "lockFileMaintenance": {
11
+ "enabled": true,
12
+ "schedule": ["before 5am on monday"]
13
+ }
14
+ }
package/src/cli.ts CHANGED
@@ -4,6 +4,8 @@ import packageJson from '../package.json';
4
4
  import { registerInitCommand } from './commands/init';
5
5
  import { registerPrepareReleaseCommand } from './commands/prepare-release';
6
6
  import { registerSetupHuskyCommand } from './commands/setup-husky';
7
+ import { registerSetupRenovateCommand } from './commands/setup-renovate';
8
+ import { registerSetupTagprCommand } from './commands/setup-tagpr';
7
9
 
8
10
  const { version: VERSION, name: NAME } = packageJson;
9
11
 
@@ -18,6 +20,8 @@ export function createProgram(): Command {
18
20
  registerInitCommand(program);
19
21
  registerPrepareReleaseCommand(program);
20
22
  registerSetupHuskyCommand(program);
23
+ registerSetupRenovateCommand(program);
24
+ registerSetupTagprCommand(program);
21
25
 
22
26
  return program;
23
27
  }
@@ -0,0 +1,138 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import type { Command } from 'commander';
4
+ import type { GeneratedFile } from '../generators/project';
5
+ import { loadTemplate } from '../generators/project';
6
+
7
+ export interface SetupRenovateOptions {
8
+ /** Target directory (defaults to current directory) */
9
+ targetDir?: string;
10
+ /** Force overwrite existing files */
11
+ force?: boolean;
12
+ }
13
+
14
+ /**
15
+ * Check if file exists
16
+ */
17
+ async function fileExists(filePath: string): Promise<boolean> {
18
+ try {
19
+ await fs.access(filePath);
20
+ return true;
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Generate renovate configuration
28
+ */
29
+ function generateRenovateSetup(): GeneratedFile[] {
30
+ return [
31
+ {
32
+ path: 'renovate.json5',
33
+ content: loadTemplate('common/renovate.json5.ejs', {}),
34
+ },
35
+ ];
36
+ }
37
+
38
+ /**
39
+ * Write generated files to target directory
40
+ */
41
+ async function writeFiles(
42
+ targetDir: string,
43
+ files: GeneratedFile[],
44
+ force: boolean,
45
+ ): Promise<{ written: string[]; skipped: string[] }> {
46
+ const written: string[] = [];
47
+ const skipped: string[] = [];
48
+
49
+ for (const file of files) {
50
+ const filePath = path.join(targetDir, file.path);
51
+ const fileDir = path.dirname(filePath);
52
+
53
+ // Check if file exists
54
+ if (!force && (await fileExists(filePath))) {
55
+ skipped.push(file.path);
56
+ continue;
57
+ }
58
+
59
+ // Create directory if needed
60
+ await fs.mkdir(fileDir, { recursive: true });
61
+
62
+ // Write file
63
+ await fs.writeFile(filePath, file.content, 'utf-8');
64
+ written.push(file.path);
65
+ }
66
+
67
+ return { written, skipped };
68
+ }
69
+
70
+ /**
71
+ * Main setup-renovate logic
72
+ */
73
+ export async function setupRenovate(
74
+ options: SetupRenovateOptions,
75
+ ): Promise<void> {
76
+ const targetDir = options.targetDir ?? process.cwd();
77
+ const force = options.force ?? false;
78
+
79
+ // Check if package.json exists
80
+ const packageJsonPath = path.join(targetDir, 'package.json');
81
+ if (!(await fileExists(packageJsonPath))) {
82
+ throw new Error('package.json not found. Are you in a project directory?');
83
+ }
84
+
85
+ console.log('🔧 Setting up Renovate configuration...\n');
86
+
87
+ // Generate renovate files
88
+ const files = generateRenovateSetup();
89
+
90
+ // Write files
91
+ const { written, skipped } = await writeFiles(targetDir, files, force);
92
+
93
+ // Report results
94
+ if (written.length > 0) {
95
+ console.log('✅ Created files:');
96
+ for (const file of written) {
97
+ console.log(` ${file}`);
98
+ }
99
+ }
100
+
101
+ if (skipped.length > 0) {
102
+ console.log('\n⏭️ Skipped (already exist, use --force to overwrite):');
103
+ for (const file of skipped) {
104
+ console.log(` ${file}`);
105
+ }
106
+ }
107
+
108
+ console.log('\n🎉 Renovate setup complete!');
109
+ console.log('\n📋 Next steps:');
110
+ console.log(
111
+ ' 1. Install Renovate GitHub App: https://github.com/apps/renovate',
112
+ );
113
+ console.log(' 2. Grant access to this repository');
114
+ }
115
+
116
+ export function registerSetupRenovateCommand(program: Command): void {
117
+ program
118
+ .command('setup-renovate')
119
+ .description('Set up Renovate configuration in an existing project')
120
+ .option(
121
+ '-t, --target-dir <path>',
122
+ 'Target directory (defaults to current directory)',
123
+ )
124
+ .option('-f, --force', 'Overwrite existing files')
125
+ .action(async (opts: { targetDir?: string; force?: boolean }) => {
126
+ try {
127
+ await setupRenovate({
128
+ targetDir: opts.targetDir,
129
+ force: opts.force,
130
+ });
131
+ } catch (error) {
132
+ console.error(
133
+ `❌ Failed to setup Renovate: ${error instanceof Error ? error.message : String(error)}`,
134
+ );
135
+ process.exit(1);
136
+ }
137
+ });
138
+ }
@@ -0,0 +1,147 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import type { Command } from 'commander';
4
+ import type { GeneratedFile } from '../generators/project';
5
+ import { loadTemplate } from '../generators/project';
6
+ import { getLatestActionVersions } from '../utils/github';
7
+
8
+ export interface SetupTagprOptions {
9
+ /** Target directory (defaults to current directory) */
10
+ targetDir?: string;
11
+ /** Force overwrite existing files */
12
+ force?: boolean;
13
+ }
14
+
15
+ /**
16
+ * Check if file exists
17
+ */
18
+ async function fileExists(filePath: string): Promise<boolean> {
19
+ try {
20
+ await fs.access(filePath);
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Generate tagpr-related files
29
+ */
30
+ async function generateTagprSetup(): Promise<GeneratedFile[]> {
31
+ const actionVersions = await getLatestActionVersions();
32
+
33
+ return [
34
+ {
35
+ path: '.tagpr',
36
+ content: loadTemplate('typescript/.tagpr.ejs', {}),
37
+ },
38
+ {
39
+ path: '.github/workflows/tagpr.yml',
40
+ content: loadTemplate('common/workflows/tagpr.yml.ejs', {
41
+ isDevcode: false,
42
+ actionVersions,
43
+ }),
44
+ },
45
+ ];
46
+ }
47
+
48
+ /**
49
+ * Write generated files to target directory
50
+ */
51
+ async function writeFiles(
52
+ targetDir: string,
53
+ files: GeneratedFile[],
54
+ force: boolean,
55
+ ): Promise<{ written: string[]; skipped: string[] }> {
56
+ const written: string[] = [];
57
+ const skipped: string[] = [];
58
+
59
+ for (const file of files) {
60
+ const filePath = path.join(targetDir, file.path);
61
+ const fileDir = path.dirname(filePath);
62
+
63
+ // Check if file exists
64
+ if (!force && (await fileExists(filePath))) {
65
+ skipped.push(file.path);
66
+ continue;
67
+ }
68
+
69
+ // Create directory if needed
70
+ await fs.mkdir(fileDir, { recursive: true });
71
+
72
+ // Write file
73
+ await fs.writeFile(filePath, file.content, 'utf-8');
74
+ written.push(file.path);
75
+ }
76
+
77
+ return { written, skipped };
78
+ }
79
+
80
+ /**
81
+ * Main setup-tagpr logic
82
+ */
83
+ export async function setupTagpr(options: SetupTagprOptions): Promise<void> {
84
+ const targetDir = options.targetDir ?? process.cwd();
85
+ const force = options.force ?? false;
86
+
87
+ // Check if package.json exists
88
+ const packageJsonPath = path.join(targetDir, 'package.json');
89
+ if (!(await fileExists(packageJsonPath))) {
90
+ throw new Error('package.json not found. Are you in a project directory?');
91
+ }
92
+
93
+ console.log('🔧 Setting up tagpr configuration...\n');
94
+
95
+ // Generate tagpr files
96
+ const files = await generateTagprSetup();
97
+
98
+ // Write files
99
+ const { written, skipped } = await writeFiles(targetDir, files, force);
100
+
101
+ // Report results
102
+ if (written.length > 0) {
103
+ console.log('✅ Created files:');
104
+ for (const file of written) {
105
+ console.log(` ${file}`);
106
+ }
107
+ }
108
+
109
+ if (skipped.length > 0) {
110
+ console.log('\n⏭️ Skipped (already exist, use --force to overwrite):');
111
+ for (const file of skipped) {
112
+ console.log(` ${file}`);
113
+ }
114
+ }
115
+
116
+ console.log('\n🎉 Tagpr setup complete!');
117
+ console.log('\n📋 Required secrets:');
118
+ console.log(
119
+ ' PAT_FOR_TAGPR - Personal Access Token with repo & workflow permissions',
120
+ );
121
+ console.log(' SSH_SIGNING_KEY - SSH private key for commit signing');
122
+ console.log(' GIT_USER_EMAIL - Email address for commits (optional)');
123
+ }
124
+
125
+ export function registerSetupTagprCommand(program: Command): void {
126
+ program
127
+ .command('setup-tagpr')
128
+ .description('Set up tagpr configuration in an existing project')
129
+ .option(
130
+ '-t, --target-dir <path>',
131
+ 'Target directory (defaults to current directory)',
132
+ )
133
+ .option('-f, --force', 'Overwrite existing files')
134
+ .action(async (opts: { targetDir?: string; force?: boolean }) => {
135
+ try {
136
+ await setupTagpr({
137
+ targetDir: opts.targetDir,
138
+ force: opts.force,
139
+ });
140
+ } catch (error) {
141
+ console.error(
142
+ `❌ Failed to setup tagpr: ${error instanceof Error ? error.message : String(error)}`,
143
+ );
144
+ process.exit(1);
145
+ }
146
+ });
147
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": ["config:recommended"],
4
+ "packageRules": [
5
+ {
6
+ "matchUpdateTypes": ["major", "minor", "patch"],
7
+ "automerge": true
8
+ }
9
+ ],
10
+ "lockFileMaintenance": {
11
+ "enabled": true,
12
+ "schedule": ["before 5am on monday"]
13
+ }
14
+ }
@@ -1,11 +0,0 @@
1
- # To get started with Dependabot version updates, you'll need to specify which
2
- # package ecosystems to update and where the package manifests are located.
3
- # Please see the documentation for all configuration options:
4
- # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
-
6
- version: 2
7
- updates:
8
- - package-ecosystem: "npm" # See documentation for possible values
9
- directory: "/" # Location of package manifests
10
- schedule:
11
- interval: "weekly"