code-foundry 0.1.0
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.
- package/.editorconfig +18 -0
- package/.env.example +3 -0
- package/.gitattributes +9 -0
- package/.githooks/pre-commit +52 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/CODE_OF_CONDUCT.md +41 -0
- package/.github/CONTRIBUTING.md +194 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +56 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +29 -0
- package/.github/SECURITY.md +23 -0
- package/.github/actions/setup/action.yml +20 -0
- package/.github/dependabot.yml +42 -0
- package/.github/scripts/bootstrap.sh +13 -0
- package/.github/scripts/ci.sh +245 -0
- package/.github/scripts/codeql-languages.sh +22 -0
- package/.github/scripts/doctor.sh +103 -0
- package/.github/scripts/init-repo.sh +109 -0
- package/.github/scripts/security.sh +51 -0
- package/.github/scripts/sitecustomize.py +17 -0
- package/.github/scripts/sync-protection.sh +124 -0
- package/.github/scripts/sync-template.sh +242 -0
- package/.github/template.yml.example +5 -0
- package/.github/workflows/ci.yml +72 -0
- package/.github/workflows/codeql.yml +56 -0
- package/.github/workflows/draft-pr.yml +62 -0
- package/.github/workflows/publish.yml +25 -0
- package/.github/workflows/release-pr.yml +61 -0
- package/.github/workflows/release.yml +23 -0
- package/.github/workflows/security.yml +38 -0
- package/.github/workflows/test.yml +84 -0
- package/.gitignore +73 -0
- package/.mise.toml +8 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +154 -0
- package/LICENSE +616 -0
- package/NOTICE +7 -0
- package/README.md +94 -0
- package/package.json +42 -0
- package/ruff.toml +6 -0
- package/src/cli.mjs +134 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Repo Foundry
|
|
2
|
+
|
|
3
|
+
`repo-foundry` is a repository factory for TypeScript, Rust, Python, Solidity,
|
|
4
|
+
and mixed-language projects. It installs agent-ready instructions, fast native
|
|
5
|
+
testing, security automation, release workflows, hooks, and repository policy
|
|
6
|
+
from one versioned package.
|
|
7
|
+
|
|
8
|
+
## Quick start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx repo-foundry init
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or select the project profile explicitly:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx repo-foundry init \
|
|
18
|
+
--languages typescript,python \
|
|
19
|
+
--features all \
|
|
20
|
+
--package-manager bun
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `repo-foundry sync` to update an existing repository and
|
|
24
|
+
`repo-foundry doctor` to validate it. Add `--dry-run` to preview changes.
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
1. Install [mise](https://mise.jdx.dev/).
|
|
29
|
+
2. Run `bash .github/scripts/bootstrap.sh` to install the pinned toolchain, enable hooks, and validate the repository.
|
|
30
|
+
3. Add the repository's standard scripts (`format:check`, `lint`, `type-check`, `build`, `test:unit`, `test:integration`, `test:e2e`, and `test:smoke`) when available. The shared scripts also recognize legacy aliases and skip checks that do not apply to the repository's languages or package manager.
|
|
31
|
+
|
|
32
|
+
## Applying the baseline to an existing repository
|
|
33
|
+
|
|
34
|
+
Run the sync script from the repository root. It updates shared workflows, GitHub forms, hooks, policy files, and tool configuration while preserving the repository's README, `.mise.toml` selections, extra workflows, and application code.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bash .github/scripts/init-repo.sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `bash .github/scripts/sync-template.sh --source ... --check` to preview differences. For local template development, pass the template checkout as `--source` and `--ref staging`.
|
|
41
|
+
|
|
42
|
+
The initializer is intentionally flag-driven so the same baseline can be used as a small repository package. Language selection controls CodeQL and records the repository profile; feature selection controls which standard workflows are installed. `auto` detects supported languages, while `all` enables every standard workflow.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Preview a TypeScript + Python repository without changing files
|
|
46
|
+
bash .github/scripts/init-repo.sh \
|
|
47
|
+
--languages typescript,python \
|
|
48
|
+
--features all \
|
|
49
|
+
--dry-run
|
|
50
|
+
|
|
51
|
+
# Initialize a Rust repository with only the core automation
|
|
52
|
+
bash .github/scripts/init-repo.sh \
|
|
53
|
+
--languages rust \
|
|
54
|
+
--features ci,codeql,security,test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Supported languages are `typescript`, `rust`, `python`, and `solidity`. Supported feature flags are `ci`, `codeql`, `security`, `test`, `draft-pr`, `release-pr`, `release`, and `dependabot`. Use `--prune` only when you explicitly want disabled standard workflows removed; custom workflows are always preserved. The selected profile is stored in `.github/template.yml`, which makes later syncs repeatable and lets workflows consume repository-specific settings without duplicating the template scripts.
|
|
58
|
+
|
|
59
|
+
For a repository that does not yet contain the scripts, the initializer can be invoked directly from the published template checkout or a downloaded copy of `init-repo.sh`; it fetches the matching sync helper automatically. The generated `.github/template.yml` is the stable configuration contract for a future npm/package wrapper around these same operations.
|
|
60
|
+
|
|
61
|
+
Branch protection is an administrator operation and is opt-in:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bash .github/scripts/init-repo.sh --protection
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The protection helper preserves unrelated provider checks, replaces stale template check names, and skips CodeQL analysis checks for private repositories where the workflow is intentionally skipped.
|
|
68
|
+
|
|
69
|
+
The repository name, owner, branch names, and release metadata are resolved by GitHub Actions at runtime through `${{ github.* }}` values. Keep organization-specific details out of this baseline.
|
|
70
|
+
|
|
71
|
+
CI and hooks use Prettier and ESLint for JavaScript/TypeScript, default `rustfmt` and Clippy with warnings-as-errors for Rust, and Ruff formatting/linting for Python.
|
|
72
|
+
|
|
73
|
+
Coverage is enforced at 80% for Python and Bun test suites when those ecosystems expose coverage support. Rust projects must keep their native test suites green; repositories with `cargo-llvm-cov` should enforce the same 80% line target in their Cargo coverage configuration.
|
|
74
|
+
|
|
75
|
+
## Test runner standard
|
|
76
|
+
|
|
77
|
+
For TypeScript and JavaScript tests, use Bun's native test runner by default. Do not add Vitest to projects based on this template. Preserve specialized native runners such as Matchstick for The Graph and Hardhat for smart contracts.
|
|
78
|
+
|
|
79
|
+
## Optional Turborepo remote caching
|
|
80
|
+
|
|
81
|
+
Turborepo repositories can use Vercel Remote Caching without changing the workflows. Add these repository settings:
|
|
82
|
+
|
|
83
|
+
- Secret: `TURBO_TOKEN`
|
|
84
|
+
- Repository variable: `TURBO_TEAM`
|
|
85
|
+
|
|
86
|
+
CI and Test pass those values to every job. Non-Turborepo repositories and repositories without the settings simply use their normal local cache behavior. This does not require the repository to deploy to Vercel.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
Unless a repository says otherwise, new material is licensed under the GNU Affero General Public License v3.0-or-later. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
91
|
+
|
|
92
|
+
## GitHub security behavior
|
|
93
|
+
|
|
94
|
+
The CodeQL workflow uses GitHub's official CodeQL actions, detects Actions, TypeScript, Python, and Rust automatically, and runs each language in parallel. It runs automatically for public repositories and skips itself for private repositories unless GitHub Code Security is enabled. Dependency Review is isolated in the Security workflow and runs only for public pull requests.
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-foundry",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "AGPL-3.0-or-later",
|
|
7
|
+
"packageManager": "bun@1.3.14",
|
|
8
|
+
"bin": {
|
|
9
|
+
"code-foundry": "src/cli.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
".github",
|
|
14
|
+
".githooks",
|
|
15
|
+
".editorconfig",
|
|
16
|
+
".gitattributes",
|
|
17
|
+
".gitignore",
|
|
18
|
+
".mise.toml",
|
|
19
|
+
".prettierrc",
|
|
20
|
+
".env.example",
|
|
21
|
+
"AGENTS.md",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"NOTICE",
|
|
24
|
+
"README.md",
|
|
25
|
+
"ruff.toml"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "node --check src/cli.mjs",
|
|
32
|
+
"format:check": "node --check src/cli.mjs",
|
|
33
|
+
"lint": "node --check src/cli.mjs",
|
|
34
|
+
"test": "node --check src/cli.mjs",
|
|
35
|
+
"type-check": "node --check src/cli.mjs",
|
|
36
|
+
"pack:check": "npm pack --dry-run",
|
|
37
|
+
"prepublishOnly": "npm test && npm run pack:check"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/ruff.toml
ADDED
package/src/cli.mjs
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { resolve } from 'node:path'
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
|
|
8
|
+
const packageRoot = resolve(fileURLToPath(new URL('..', import.meta.url)))
|
|
9
|
+
|
|
10
|
+
const usage = `repo-foundry — initialize and maintain agent-ready repositories
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
repo-foundry init [options]
|
|
14
|
+
repo-foundry sync [options]
|
|
15
|
+
repo-foundry doctor [--target PATH]
|
|
16
|
+
|
|
17
|
+
Init/sync options:
|
|
18
|
+
--target PATH Repository directory (default: current directory)
|
|
19
|
+
--source PATH_OR_URL Template source override
|
|
20
|
+
--ref REF Template branch or tag (default: main)
|
|
21
|
+
--languages LIST auto or typescript,rust,python,solidity
|
|
22
|
+
--features LIST all or ci,codeql,security,test,draft-pr,release-pr,release,dependabot
|
|
23
|
+
--package-manager NAME auto, bun, pnpm, yarn, or npm
|
|
24
|
+
--dry-run Preview changes without writing files
|
|
25
|
+
--prune Remove disabled standard workflows
|
|
26
|
+
--protection Synchronize main branch protections (init only)
|
|
27
|
+
--no-bootstrap Skip mise/hooks/doctor bootstrap after init
|
|
28
|
+
-h, --help Show this help
|
|
29
|
+
`
|
|
30
|
+
|
|
31
|
+
function fail(message) {
|
|
32
|
+
console.error(`repo-foundry: ${message}`)
|
|
33
|
+
process.exit(2)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseArgs(argv) {
|
|
37
|
+
const command = argv[0] && !argv[0].startsWith('-') ? argv.shift() : 'init'
|
|
38
|
+
const options = {
|
|
39
|
+
target: process.cwd(),
|
|
40
|
+
source: packageRoot,
|
|
41
|
+
ref: 'main',
|
|
42
|
+
languages: 'auto',
|
|
43
|
+
features: 'all',
|
|
44
|
+
packageManager: 'auto',
|
|
45
|
+
dryRun: false,
|
|
46
|
+
prune: false,
|
|
47
|
+
protection: false,
|
|
48
|
+
bootstrap: true,
|
|
49
|
+
}
|
|
50
|
+
const values = new Map([
|
|
51
|
+
['--target', 'target'],
|
|
52
|
+
['--source', 'source'],
|
|
53
|
+
['--ref', 'ref'],
|
|
54
|
+
['--languages', 'languages'],
|
|
55
|
+
['--features', 'features'],
|
|
56
|
+
['--package-manager', 'packageManager'],
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
while (argv.length) {
|
|
60
|
+
const arg = argv.shift()
|
|
61
|
+
if (arg === '-h' || arg === '--help') {
|
|
62
|
+
console.log(usage)
|
|
63
|
+
process.exit(0)
|
|
64
|
+
}
|
|
65
|
+
if (values.has(arg)) {
|
|
66
|
+
const value = argv.shift()
|
|
67
|
+
if (!value || value.startsWith('-')) fail(`${arg} requires a value`)
|
|
68
|
+
options[values.get(arg)] = value
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
if (arg === '--dry-run') options.dryRun = true
|
|
72
|
+
else if (arg === '--prune') options.prune = true
|
|
73
|
+
else if (arg === '--protection') options.protection = true
|
|
74
|
+
else if (arg === '--no-bootstrap') options.bootstrap = false
|
|
75
|
+
else fail(`unknown option: ${arg}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { command, options }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function run(script, args, target) {
|
|
82
|
+
const scriptPath = resolve(packageRoot, '.github/scripts', script)
|
|
83
|
+
if (!existsSync(scriptPath)) fail(`package is missing ${script}`)
|
|
84
|
+
const result = spawnSync('bash', [scriptPath, ...args], {
|
|
85
|
+
cwd: target,
|
|
86
|
+
stdio: 'inherit',
|
|
87
|
+
env: process.env,
|
|
88
|
+
})
|
|
89
|
+
if (result.error) fail(result.error.message)
|
|
90
|
+
if (result.status !== 0) process.exit(result.status ?? 1)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function main() {
|
|
94
|
+
const { command, options } = parseArgs(process.argv.slice(2))
|
|
95
|
+
const target = resolve(options.target)
|
|
96
|
+
const common = [
|
|
97
|
+
'--source', options.source,
|
|
98
|
+
'--ref', options.ref,
|
|
99
|
+
'--languages', options.languages,
|
|
100
|
+
'--features', options.features,
|
|
101
|
+
]
|
|
102
|
+
if (options.prune) common.push('--prune')
|
|
103
|
+
if (options.dryRun) common.push('--check')
|
|
104
|
+
else common.push('--apply')
|
|
105
|
+
|
|
106
|
+
if (command === 'init') {
|
|
107
|
+
const initArgs = [...common]
|
|
108
|
+
if (options.protection) initArgs.push('--protection')
|
|
109
|
+
if (!options.bootstrap) {
|
|
110
|
+
// The shell initializer is intentionally composable; sync first and let
|
|
111
|
+
// callers run bootstrap separately when installing into a CI image.
|
|
112
|
+
run('sync-template.sh', initArgs, target)
|
|
113
|
+
} else {
|
|
114
|
+
run('init-repo.sh', [
|
|
115
|
+
'--source', options.source,
|
|
116
|
+
'--ref', options.ref,
|
|
117
|
+
'--languages', options.languages,
|
|
118
|
+
'--features', options.features,
|
|
119
|
+
'--package-manager', options.packageManager,
|
|
120
|
+
...(options.dryRun ? ['--dry-run'] : []),
|
|
121
|
+
...(options.prune ? ['--prune'] : []),
|
|
122
|
+
...(options.protection ? ['--protection'] : []),
|
|
123
|
+
], target)
|
|
124
|
+
}
|
|
125
|
+
} else if (command === 'sync') {
|
|
126
|
+
run('sync-template.sh', common, target)
|
|
127
|
+
} else if (command === 'doctor') {
|
|
128
|
+
run('doctor.sh', [], target)
|
|
129
|
+
} else {
|
|
130
|
+
fail(`unknown command: ${command}`)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
main()
|