cistack 3.2.0 → 5.0.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/.github/workflows/ci.yml +70 -0
- package/README.md +183 -124
- package/bin/ciflow.js +3 -2
- package/index.d.ts +91 -0
- package/package.json +4 -2
- package/src/analyzers/codebase.js +43 -6
- package/src/analyzers/monorepo.js +7 -7
- package/src/analyzers/workflow.js +10 -2
- package/src/config/loader.js +66 -10
- package/src/detectors/framework.js +29 -25
- package/src/detectors/hosting.js +25 -10
- package/src/detectors/language.js +2 -2
- package/src/detectors/release.js +29 -8
- package/src/detectors/testing.js +18 -2
- package/src/generators/dependabot.js +24 -3
- package/src/generators/release.js +25 -10
- package/src/generators/workflow.js +330 -99
- package/src/index.js +33 -18
- package/src/utils/helpers.js +21 -7
- package/src/utils/workflow-combiner.js +238 -0
- package/tests/run.js +934 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
name: Node ${{ matrix.node-version }}
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
node-version:
|
|
22
|
+
- 18.x
|
|
23
|
+
- 20.x
|
|
24
|
+
- 22.x
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Node.js
|
|
31
|
+
uses: actions/setup-node@v4
|
|
32
|
+
with:
|
|
33
|
+
node-version: ${{ matrix.node-version }}
|
|
34
|
+
cache: npm
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: npm ci
|
|
38
|
+
|
|
39
|
+
- name: Run package smoke test
|
|
40
|
+
run: npm test
|
|
41
|
+
|
|
42
|
+
- name: Verify audit command
|
|
43
|
+
run: node bin/ciflow.js audit --path .
|
|
44
|
+
|
|
45
|
+
- name: Verify upgrade command
|
|
46
|
+
run: node bin/ciflow.js upgrade --path . --dry-run
|
|
47
|
+
|
|
48
|
+
- name: Smoke test init command in temp workspace
|
|
49
|
+
shell: bash
|
|
50
|
+
run: |
|
|
51
|
+
set -euo pipefail
|
|
52
|
+
tmp_dir="$(mktemp -d)"
|
|
53
|
+
node bin/ciflow.js init --path "$tmp_dir"
|
|
54
|
+
test -f "$tmp_dir/cistack.config.js"
|
|
55
|
+
|
|
56
|
+
- name: Smoke test generate command in temp workspace
|
|
57
|
+
shell: bash
|
|
58
|
+
run: |
|
|
59
|
+
set -euo pipefail
|
|
60
|
+
tmp_dir="$(mktemp -d)"
|
|
61
|
+
cat > "$tmp_dir/package.json" <<'JSON'
|
|
62
|
+
{
|
|
63
|
+
"name": "fixture-app",
|
|
64
|
+
"version": "1.0.0",
|
|
65
|
+
"scripts": {
|
|
66
|
+
"test": "echo ok"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
JSON
|
|
70
|
+
node bin/ciflow.js generate --path "$tmp_dir" --dry-run --no-prompt
|
package/README.md
CHANGED
|
@@ -1,186 +1,245 @@
|
|
|
1
1
|
# cistack
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Generate GitHub Actions CI/CD pipelines by analyzing the codebase you already have.
|
|
4
4
|
|
|
5
|
-
`cistack` scans your project
|
|
5
|
+
`cistack` scans your project, detects the stack, and writes production-ready GitHub Actions workflows for CI, deployment, Docker, security, and releases. It is designed for real repos, not toy demos: it reads lock files, framework signals, release config, monorepo workspaces, hosting config, and Git branch metadata before generating YAML.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Why cistack
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- 🔒 **Security built-in** — CodeQL analysis + dependency auditing on every pipeline
|
|
19
|
-
- 📦 **Monorepo aware** — detects Turborepo, Nx, Lerna, pnpm workspaces (supports per-package workflows)
|
|
20
|
-
- ✅ **Interactive mode** — confirms detected settings before writing files
|
|
21
|
-
- 🎯 **Zero config** — works out of the box with `cistack.config.js` for overrides
|
|
22
|
-
|
|
23
|
-
---
|
|
9
|
+
- Detects languages, frameworks, testing tools, hosting providers, and release tooling automatically
|
|
10
|
+
- Uses your repository's default Git branch when available instead of assuming `main`
|
|
11
|
+
- Supports monorepos, per-package workflows, and package-manager-aware commands
|
|
12
|
+
- Generates ecosystem-aware Dependabot config, including Bun when `bun.lock` is present
|
|
13
|
+
- Smart-merges generated workflows with existing files instead of blindly overwriting them
|
|
14
|
+
- Generates deploy pipelines for Vercel, Netlify, Firebase, GitHub Pages, AWS, Azure, Heroku, Render, and Railway
|
|
15
|
+
- Ships with built-in workflow audit and upgrade commands
|
|
16
|
+
- Includes typed `cistack.config.js` support through `index.d.ts`
|
|
17
|
+
- Backed by an automated regression suite covering branch handling, release detection, smart merge behavior, monorepo package scripts, and CLI smoke tests
|
|
24
18
|
|
|
25
19
|
## Installation
|
|
26
20
|
|
|
27
21
|
```bash
|
|
28
|
-
#
|
|
22
|
+
# One-off usage
|
|
29
23
|
npx cistack
|
|
30
24
|
|
|
31
|
-
#
|
|
25
|
+
# Global install
|
|
32
26
|
npm install -g cistack
|
|
33
27
|
```
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
`cistack` supports Node.js 16+, and the project itself is continuously verified on Node.js 18, 20, and 22 in GitHub Actions.
|
|
36
30
|
|
|
37
|
-
## Usage
|
|
31
|
+
## CLI Usage
|
|
38
32
|
|
|
39
|
-
### Generate
|
|
40
|
-
Analyze your stack and generate best-practice workflows.
|
|
41
|
-
```bash
|
|
42
|
-
# In your project directory
|
|
43
|
-
npx cistack
|
|
33
|
+
### Generate workflows
|
|
44
34
|
|
|
45
|
-
|
|
46
|
-
npx cistack --explain
|
|
35
|
+
`generate` is the default command, so both of these work:
|
|
47
36
|
|
|
48
|
-
|
|
49
|
-
npx cistack
|
|
37
|
+
```bash
|
|
38
|
+
npx cistack
|
|
39
|
+
npx cistack generate
|
|
40
|
+
```
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
npx cistack --output .github/workflows
|
|
42
|
+
Common options:
|
|
53
43
|
|
|
54
|
-
|
|
55
|
-
npx cistack --
|
|
44
|
+
```bash
|
|
45
|
+
npx cistack generate --path /path/to/project
|
|
46
|
+
npx cistack generate --dry-run
|
|
47
|
+
npx cistack generate --explain
|
|
48
|
+
npx cistack generate --output .github/workflows
|
|
49
|
+
npx cistack generate --no-prompt
|
|
56
50
|
```
|
|
57
51
|
|
|
58
|
-
### Audit
|
|
59
|
-
|
|
52
|
+
### Audit existing workflows
|
|
53
|
+
|
|
60
54
|
```bash
|
|
61
55
|
npx cistack audit
|
|
62
56
|
```
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
This checks `.github/workflows` for issues like missing concurrency blocks, outdated actions, old Node versions, and missing dependency caching.
|
|
59
|
+
|
|
60
|
+
### Upgrade workflow actions
|
|
61
|
+
|
|
66
62
|
```bash
|
|
67
63
|
npx cistack upgrade
|
|
64
|
+
npx cistack upgrade --dry-run
|
|
68
65
|
```
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
This updates known GitHub Actions to their latest supported stable versions.
|
|
68
|
+
|
|
69
|
+
### Create a starter config
|
|
70
|
+
|
|
72
71
|
```bash
|
|
73
72
|
npx cistack init
|
|
74
73
|
```
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
This writes `cistack.config.js` with the supported override keys.
|
|
77
76
|
|
|
78
|
-
##
|
|
77
|
+
## What gets generated
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
- `--dry-run` — Print YAML to terminal without writing to disk
|
|
82
|
-
- `--force` — Overwrite existing files instead of smart-merging
|
|
83
|
-
- `--no-prompt` — Skip interactive confirmation
|
|
84
|
-
- `--verbose` — Show raw analysis data
|
|
85
|
-
- `--path <dir>` — Project root directory
|
|
86
|
-
- `--output <dir>` — Workflow output directory (default: `.github/workflows`)
|
|
79
|
+
### `pipeline.yml`
|
|
87
80
|
|
|
88
|
-
|
|
81
|
+
By default, `cistack` now generates a single GitHub Actions workflow that combines CI, deploy, Docker, security, and release jobs into one place so teams can track the whole pipeline from one file.
|
|
89
82
|
|
|
90
|
-
|
|
83
|
+
- Includes lint, test, build, E2E, deploy, Docker, security, and release jobs when those parts of the stack are detected
|
|
84
|
+
- Uses the detected default branch or your configured `branches`
|
|
85
|
+
- Keeps preview deploys, release jobs, and scheduled security scans in the same workflow file
|
|
86
|
+
- Documents required secrets in the file header
|
|
91
87
|
|
|
92
|
-
|
|
93
|
-
|---|---|
|
|
94
|
-
| **Firebase** | `firebase.json`, `.firebaserc`, `firebase-tools` dep |
|
|
95
|
-
| **Vercel** | `vercel.json`, `.vercel` dir, `vercel` dep |
|
|
96
|
-
| **Netlify** | `netlify.toml`, `_redirects`, `netlify-cli` dep |
|
|
97
|
-
| **GitHub Pages** | `gh-pages` dep, `github.io` homepage in `package.json` |
|
|
98
|
-
| **AWS** | `serverless.yml`, `appspec.yml`, `cdk.json`, `aws-sdk` dep |
|
|
99
|
-
| **GCP App Engine** | `app.yaml` |
|
|
100
|
-
| **Azure** | `azure/pipelines.yml`, `@azure/*` deps |
|
|
101
|
-
| **Heroku** | `Procfile`, `heroku.yml` |
|
|
102
|
-
| **Render** | `render.yaml` |
|
|
103
|
-
| **Railway** | `railway.json`, `railway.toml` |
|
|
104
|
-
| **Docker** | `Dockerfile`, `docker-compose.yml` |
|
|
88
|
+
### `dependabot.yml`
|
|
105
89
|
|
|
106
|
-
|
|
90
|
+
Dependabot remains a separate file in `.github/dependabot.yml`, because it is not a GitHub Actions workflow.
|
|
107
91
|
|
|
108
|
-
|
|
92
|
+
### Split mode
|
|
109
93
|
|
|
110
|
-
|
|
111
|
-
Express, Fastify, NestJS, Hono, Koa, tRPC,
|
|
112
|
-
Django, Flask, FastAPI,
|
|
113
|
-
Ruby on Rails,
|
|
114
|
-
Spring Boot,
|
|
115
|
-
Laravel,
|
|
116
|
-
Go (gin), Rust (Cargo)
|
|
94
|
+
If you prefer the old multi-file layout, set:
|
|
117
95
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|---|---|
|
|
124
|
-
| Jest, Vitest, Mocha | Unit |
|
|
125
|
-
| Cypress, Playwright | E2E |
|
|
126
|
-
| Pytest | Python unit |
|
|
127
|
-
| RSpec | Ruby unit |
|
|
128
|
-
| Go Test | Go unit |
|
|
129
|
-
| Cargo Test | Rust unit |
|
|
130
|
-
| PHPUnit | PHP unit |
|
|
131
|
-
| JUnit/Maven | JVM unit |
|
|
132
|
-
| Storybook | Visual |
|
|
96
|
+
```js
|
|
97
|
+
module.exports = {
|
|
98
|
+
workflowLayout: 'split',
|
|
99
|
+
};
|
|
100
|
+
```
|
|
133
101
|
|
|
134
|
-
|
|
102
|
+
In split mode, `cistack` writes separate `ci.yml`, `deploy.yml`, `docker.yml`, `security.yml`, and `release.yml` files again.
|
|
103
|
+
|
|
104
|
+
## Supported detection
|
|
105
|
+
|
|
106
|
+
### Hosting
|
|
107
|
+
|
|
108
|
+
- Firebase
|
|
109
|
+
- Vercel
|
|
110
|
+
- Netlify
|
|
111
|
+
- GitHub Pages
|
|
112
|
+
- AWS
|
|
113
|
+
- GCP App Engine
|
|
114
|
+
- Azure
|
|
115
|
+
- Heroku
|
|
116
|
+
- Render
|
|
117
|
+
- Railway
|
|
118
|
+
- Docker
|
|
119
|
+
|
|
120
|
+
### Frameworks
|
|
121
|
+
|
|
122
|
+
- Next.js
|
|
123
|
+
- Nuxt
|
|
124
|
+
- SvelteKit
|
|
125
|
+
- Remix
|
|
126
|
+
- Astro
|
|
127
|
+
- Vite
|
|
128
|
+
- React
|
|
129
|
+
- Vue
|
|
130
|
+
- Angular
|
|
131
|
+
- Svelte
|
|
132
|
+
- Gatsby
|
|
133
|
+
- Express
|
|
134
|
+
- Fastify
|
|
135
|
+
- NestJS
|
|
136
|
+
- Hono
|
|
137
|
+
- Koa
|
|
138
|
+
- Django
|
|
139
|
+
- Flask
|
|
140
|
+
- FastAPI
|
|
141
|
+
- Rails
|
|
142
|
+
- Spring Boot
|
|
143
|
+
- Laravel
|
|
144
|
+
- Go
|
|
145
|
+
- Rust
|
|
146
|
+
|
|
147
|
+
### Testing tools
|
|
148
|
+
|
|
149
|
+
- Jest
|
|
150
|
+
- Vitest
|
|
151
|
+
- Mocha
|
|
152
|
+
- Cypress
|
|
153
|
+
- Playwright
|
|
154
|
+
- Pytest
|
|
155
|
+
- RSpec
|
|
156
|
+
- Go test
|
|
157
|
+
- Cargo test
|
|
158
|
+
- PHPUnit
|
|
159
|
+
- Maven / JUnit
|
|
160
|
+
- Storybook
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
Create `cistack.config.js` when you want to override detection:
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
/** @type {import('cistack').Config} */
|
|
168
|
+
module.exports = {
|
|
169
|
+
nodeVersion: '20',
|
|
170
|
+
packageManager: 'pnpm',
|
|
171
|
+
branches: ['main', 'staging'],
|
|
172
|
+
workflowLayout: 'single',
|
|
173
|
+
hosting: ['Vercel'],
|
|
174
|
+
outputDir: '.github/workflows',
|
|
175
|
+
|
|
176
|
+
cache: {
|
|
177
|
+
npm: true,
|
|
178
|
+
cargo: true,
|
|
179
|
+
pip: true,
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
monorepo: {
|
|
183
|
+
perPackage: true,
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
release: {
|
|
187
|
+
tool: 'semantic-release',
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
```
|
|
135
191
|
|
|
136
|
-
|
|
192
|
+
Supported top-level config keys:
|
|
137
193
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
194
|
+
- `nodeVersion`
|
|
195
|
+
- `packageManager`
|
|
196
|
+
- `hosting`
|
|
197
|
+
- `frameworks`
|
|
198
|
+
- `testing`
|
|
199
|
+
- `branches`
|
|
200
|
+
- `workflowLayout`
|
|
201
|
+
- `cache`
|
|
202
|
+
- `monorepo`
|
|
203
|
+
- `release`
|
|
204
|
+
- `secrets`
|
|
205
|
+
- `outputDir`
|
|
145
206
|
|
|
146
|
-
|
|
147
|
-
Triggers on push to `main`/`master` + manual dispatch:
|
|
148
|
-
- Platform-specific deploy using official GitHub Actions
|
|
149
|
-
- **PR Preview Deploys** — automatic previews for Vercel and Netlify pull requests
|
|
150
|
-
- Proper secret references documented in the file header
|
|
207
|
+
Branch behavior:
|
|
151
208
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
-
|
|
155
|
-
- Pushes to GitHub Container Registry (GHCR)
|
|
156
|
-
- Build cache via GitHub Actions cache (GHA)
|
|
209
|
+
- If `branches` is set in config, `cistack` uses it exactly
|
|
210
|
+
- Otherwise it reads the repository's default branch from Git metadata when available
|
|
211
|
+
- If Git metadata is unavailable, it falls back to safe defaults like `main`, `master`, and `develop` depending on the workflow type
|
|
157
212
|
|
|
158
|
-
|
|
159
|
-
Runs on push, PRs, and weekly schedule:
|
|
160
|
-
- Dependency vulnerability audit (npm audit / safety / cargo audit)
|
|
161
|
-
- GitHub CodeQL analysis for the detected language
|
|
213
|
+
## Secrets
|
|
162
214
|
|
|
163
|
-
|
|
215
|
+
Generated deploy and release workflows document the secrets they need at the top of each file. Add them in:
|
|
164
216
|
|
|
165
|
-
|
|
217
|
+
`GitHub -> Settings -> Secrets and variables -> Actions`
|
|
166
218
|
|
|
167
|
-
|
|
168
|
-
`Settings → Secrets and variables → Actions`
|
|
219
|
+
## Development and Quality
|
|
169
220
|
|
|
170
|
-
|
|
221
|
+
The project now includes a regression suite for the areas that were historically the easiest to break:
|
|
171
222
|
|
|
172
|
-
|
|
223
|
+
- config override handling
|
|
224
|
+
- default branch detection
|
|
225
|
+
- deploy branch selection
|
|
226
|
+
- Netlify production branch handling
|
|
227
|
+
- smart merge behavior
|
|
228
|
+
- monorepo per-package build script lookup
|
|
229
|
+
- release config detection
|
|
230
|
+
- release workflow generation
|
|
231
|
+
- CLI dry-run smoke testing
|
|
173
232
|
|
|
174
|
-
|
|
233
|
+
Run the checks locally:
|
|
175
234
|
|
|
176
|
-
**Next.js + Vercel project with Audit:**
|
|
177
235
|
```bash
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
236
|
+
npm test
|
|
237
|
+
npm run test:smoke
|
|
238
|
+
node bin/ciflow.js audit --path .
|
|
239
|
+
node bin/ciflow.js upgrade --path . --dry-run
|
|
181
240
|
```
|
|
182
241
|
|
|
183
|
-
|
|
242
|
+
If you are using the published package, the executable is `cistack`. In this repository, the local entrypoint is `bin/ciflow.js`.
|
|
184
243
|
|
|
185
244
|
## License
|
|
186
245
|
|
package/bin/ciflow.js
CHANGED
|
@@ -87,7 +87,8 @@ module.exports = {
|
|
|
87
87
|
// nodeVersion: '20', // Override detected Node.js version
|
|
88
88
|
// packageManager: 'pnpm', // 'npm' | 'yarn' | 'pnpm' | 'bun'
|
|
89
89
|
// hosting: ['Firebase'], // Force a specific hosting provider
|
|
90
|
-
// branches: ['main', 'staging'], // CI branches (default:
|
|
90
|
+
// branches: ['main', 'staging'], // CI branches (default: detected git default branch, then main/master/develop)
|
|
91
|
+
// workflowLayout: 'single', // 'single' (default) or 'split'
|
|
91
92
|
// outputDir: '.github/workflows', // Where to write workflow files
|
|
92
93
|
|
|
93
94
|
// cache: {
|
|
@@ -101,7 +102,7 @@ module.exports = {
|
|
|
101
102
|
// },
|
|
102
103
|
|
|
103
104
|
// monorepo: {
|
|
104
|
-
// perPackage: true, // Generate one ci-<name>.yml per workspace
|
|
105
|
+
// perPackage: true, // Generate one ci-<name>.yml per workspace (split layout only)
|
|
105
106
|
// },
|
|
106
107
|
|
|
107
108
|
// release: {
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type PackageManager =
|
|
2
|
+
| 'npm'
|
|
3
|
+
| 'yarn'
|
|
4
|
+
| 'pnpm'
|
|
5
|
+
| 'bun'
|
|
6
|
+
| 'pip'
|
|
7
|
+
| 'poetry'
|
|
8
|
+
| 'pipenv'
|
|
9
|
+
| 'bundler'
|
|
10
|
+
| 'go mod'
|
|
11
|
+
| 'cargo'
|
|
12
|
+
| 'maven'
|
|
13
|
+
| 'gradle'
|
|
14
|
+
| 'composer';
|
|
15
|
+
|
|
16
|
+
export type HostingName =
|
|
17
|
+
| 'Firebase'
|
|
18
|
+
| 'Vercel'
|
|
19
|
+
| 'Netlify'
|
|
20
|
+
| 'AWS'
|
|
21
|
+
| 'GCP App Engine'
|
|
22
|
+
| 'Azure'
|
|
23
|
+
| 'Heroku'
|
|
24
|
+
| 'Render'
|
|
25
|
+
| 'Railway'
|
|
26
|
+
| 'GitHub Pages'
|
|
27
|
+
| 'Docker';
|
|
28
|
+
|
|
29
|
+
export type ReleaseTool =
|
|
30
|
+
| 'semantic-release'
|
|
31
|
+
| 'changesets'
|
|
32
|
+
| 'release-it'
|
|
33
|
+
| 'standard-version'
|
|
34
|
+
| 'custom';
|
|
35
|
+
|
|
36
|
+
export interface CacheConfig {
|
|
37
|
+
npm?: boolean;
|
|
38
|
+
pip?: boolean;
|
|
39
|
+
cargo?: boolean;
|
|
40
|
+
maven?: boolean;
|
|
41
|
+
gradle?: boolean;
|
|
42
|
+
go?: boolean;
|
|
43
|
+
composer?: boolean;
|
|
44
|
+
bundler?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface MonorepoConfig {
|
|
48
|
+
perPackage?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ReleaseConfig {
|
|
52
|
+
tool: ReleaseTool;
|
|
53
|
+
command?: string;
|
|
54
|
+
publishToNpm?: boolean;
|
|
55
|
+
requiresNpmToken?: boolean;
|
|
56
|
+
branches?: string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Config {
|
|
60
|
+
nodeVersion?: string | number;
|
|
61
|
+
packageManager?: PackageManager;
|
|
62
|
+
hosting?: HostingName | HostingName[];
|
|
63
|
+
frameworks?: string | string[];
|
|
64
|
+
testing?: string | string[];
|
|
65
|
+
branches?: string[];
|
|
66
|
+
workflowLayout?: 'single' | 'split';
|
|
67
|
+
cache?: CacheConfig;
|
|
68
|
+
monorepo?: MonorepoConfig;
|
|
69
|
+
release?: ReleaseTool | ReleaseConfig;
|
|
70
|
+
secrets?: string[];
|
|
71
|
+
outputDir?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface CIFlowOptions {
|
|
75
|
+
projectPath: string;
|
|
76
|
+
outputDir?: string;
|
|
77
|
+
dryRun?: boolean;
|
|
78
|
+
force?: boolean;
|
|
79
|
+
prompt?: boolean;
|
|
80
|
+
verbose?: boolean;
|
|
81
|
+
explain?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
declare class CIFlow {
|
|
85
|
+
constructor(options: CIFlowOptions);
|
|
86
|
+
run(): Promise<void>;
|
|
87
|
+
audit(): Promise<void>;
|
|
88
|
+
upgrade(): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default CIFlow;
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cistack",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Automatically generate GitHub Actions CI/CD pipelines by analysing your codebase",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
6
7
|
"bin": {
|
|
7
8
|
"cistack": "./bin/ciflow.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
11
|
"start": "node bin/ciflow.js",
|
|
11
|
-
"test": "node
|
|
12
|
+
"test": "node tests/run.js",
|
|
13
|
+
"test:smoke": "node bin/ciflow.js generate --path . --dry-run --no-prompt"
|
|
12
14
|
},
|
|
13
15
|
"keywords": [
|
|
14
16
|
"github-actions",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const { execFileSync } = require('child_process');
|
|
5
6
|
const { globSync } = require('glob');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -25,9 +26,11 @@ class CodebaseAnalyzer {
|
|
|
25
26
|
srcStructure: {},
|
|
26
27
|
hasMonorepo: false,
|
|
27
28
|
workspaces: [],
|
|
29
|
+
defaultBranch: null,
|
|
30
|
+
currentBranch: null,
|
|
28
31
|
};
|
|
29
32
|
|
|
30
|
-
// ── gather
|
|
33
|
+
// ── gather notable file paths (avoid giant deep scans) ──────────────
|
|
31
34
|
const allFiles = globSync('**/*', {
|
|
32
35
|
cwd: this.root,
|
|
33
36
|
ignore: [
|
|
@@ -38,11 +41,16 @@ class CodebaseAnalyzer {
|
|
|
38
41
|
'.next/**',
|
|
39
42
|
'.nuxt/**',
|
|
40
43
|
'coverage/**',
|
|
44
|
+
'public/**',
|
|
45
|
+
'assets/**',
|
|
46
|
+
'static/**',
|
|
47
|
+
'vendor/**',
|
|
41
48
|
'*.min.js',
|
|
42
49
|
'*.min.css',
|
|
43
50
|
],
|
|
44
|
-
nodir:
|
|
51
|
+
nodir: false,
|
|
45
52
|
dot: true,
|
|
53
|
+
maxDepth: 5, // Avoid extreme depth for general discovery
|
|
46
54
|
});
|
|
47
55
|
|
|
48
56
|
info.files = allFiles;
|
|
@@ -60,6 +68,7 @@ class CodebaseAnalyzer {
|
|
|
60
68
|
'package-lock.json',
|
|
61
69
|
'yarn.lock',
|
|
62
70
|
'pnpm-lock.yaml',
|
|
71
|
+
'bun.lock',
|
|
63
72
|
'bun.lockb',
|
|
64
73
|
'Pipfile.lock',
|
|
65
74
|
'poetry.lock',
|
|
@@ -149,7 +158,7 @@ class CodebaseAnalyzer {
|
|
|
149
158
|
'biome.json',
|
|
150
159
|
// CI already present
|
|
151
160
|
'.travis.yml',
|
|
152
|
-
'
|
|
161
|
+
'.circleci/config.yml',
|
|
153
162
|
'Jenkinsfile',
|
|
154
163
|
];
|
|
155
164
|
|
|
@@ -188,9 +197,7 @@ class CodebaseAnalyzer {
|
|
|
188
197
|
fs.existsSync(path.join(this.root, 'turbo.json')) ||
|
|
189
198
|
fs.existsSync(path.join(this.root, 'nx.json')) ||
|
|
190
199
|
fs.existsSync(path.join(this.root, 'lerna.json')) ||
|
|
191
|
-
(info.packageJson &&
|
|
192
|
-
(info.packageJson.workspaces ||
|
|
193
|
-
info.packageJson.private === true));
|
|
200
|
+
(info.packageJson && info.packageJson.workspaces);
|
|
194
201
|
|
|
195
202
|
info.hasMonorepo = !!hasMonorepoMarker;
|
|
196
203
|
if (info.packageJson && info.packageJson.workspaces) {
|
|
@@ -198,8 +205,38 @@ class CodebaseAnalyzer {
|
|
|
198
205
|
info.workspaces = Array.isArray(ws) ? ws : ws.packages || [];
|
|
199
206
|
}
|
|
200
207
|
|
|
208
|
+
// ── git branch hints ───────────────────────────────────────────────────
|
|
209
|
+
const gitInfo = this._detectGitBranches();
|
|
210
|
+
info.defaultBranch = gitInfo.defaultBranch;
|
|
211
|
+
info.currentBranch = gitInfo.currentBranch;
|
|
212
|
+
|
|
201
213
|
return info;
|
|
202
214
|
}
|
|
215
|
+
|
|
216
|
+
_detectGitBranches() {
|
|
217
|
+
const readGit = (args) => {
|
|
218
|
+
try {
|
|
219
|
+
return execFileSync('git', args, {
|
|
220
|
+
cwd: this.root,
|
|
221
|
+
encoding: 'utf8',
|
|
222
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
223
|
+
}).trim();
|
|
224
|
+
} catch (_) {
|
|
225
|
+
return '';
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const remoteHead = readGit(['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD']);
|
|
230
|
+
const currentBranch = readGit(['symbolic-ref', '--quiet', '--short', 'HEAD']) || null;
|
|
231
|
+
const defaultBranch = remoteHead
|
|
232
|
+
? remoteHead.replace(/^origin\//, '')
|
|
233
|
+
: currentBranch;
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
defaultBranch: defaultBranch || null,
|
|
237
|
+
currentBranch,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
203
240
|
}
|
|
204
241
|
|
|
205
242
|
module.exports = CodebaseAnalyzer;
|