@kirchdev/gitignore-sync 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/LICENSE +21 -0
- package/README.md +179 -0
- package/action.yml +63 -0
- package/dist/bin/gitignore-sync.mjs +1539 -0
- package/dist/bin/gitignore-sync.mjs.map +1 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Titus Kirch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ๐งฐ gitignore-sync
|
|
4
|
+
|
|
5
|
+
**Keeps your `.gitignore` maintained, not generated โ curated blocks in a region the tool owns, everything else untouched**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@kirchdev/gitignore-sync)
|
|
8
|
+
[](https://www.npmjs.com/package/@kirchdev/gitignore-sync)
|
|
9
|
+
[](https://github.com/kirchDev/gitignore-sync/actions/workflows/ci.yml)
|
|
10
|
+
[](https://www.npmjs.com/package/@kirchdev/gitignore-sync)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx @kirchdev/gitignore-sync init # fingerprint the repo, confirm, write the region
|
|
19
|
+
npx @kirchdev/gitignore-sync sync # re-render it, any time, as often as you like
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
That's it. The blocks the tool owns stay current; every line you wrote yourself survives verbatim.
|
|
23
|
+
|
|
24
|
+
## ๐ค Why
|
|
25
|
+
|
|
26
|
+
`gitignore.io`, `gig` and `ignr` all _fetch and dump_: you pull a template once, paste it, and drift from there. None of them re-syncs, so a `.gitignore` grows into a few hundred lines of ballast nobody dares touch.
|
|
27
|
+
|
|
28
|
+
`gitignore-sync` keeps a **managed region** inside the file and re-renders it on demand. The rest of the file is a free zone the tool never writes to โ which is what makes running it a second time safe, and a hundredth time boring.
|
|
29
|
+
|
|
30
|
+
## ๐ฆ Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm add -g @kirchdev/gitignore-sync # npm i -g / yarn global add / bun add -g all work
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or run it without installing: `npx @kirchdev/gitignore-sync <command>`. The binary is also available as `gis`.
|
|
37
|
+
|
|
38
|
+
## ๐ Quick start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gitignore-sync init # detect, confirm in a prompt, write the region
|
|
42
|
+
gitignore-sync edit # tick stacks on and off later
|
|
43
|
+
gitignore-sync add nuxt tauri # or name them โ for scripts and CI
|
|
44
|
+
gitignore-sync remove intellij # drop one; your own lines are kept
|
|
45
|
+
gitignore-sync sync # re-render from the header
|
|
46
|
+
gitignore-sync check # CI gate: non-zero on drift
|
|
47
|
+
gitignore-sync list # what this binary ships, and what you declare
|
|
48
|
+
gitignore-sync info # which build is running, and what it sees
|
|
49
|
+
gitignore-sync audit ../*/ # how much of a whole estate the stacks cover
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Every command takes `--help` and a directory (`--dir` for `add`/`remove`, positional elsewhere), and every writing command takes `--dry-run`.
|
|
53
|
+
|
|
54
|
+
> [!TIP]
|
|
55
|
+
> `init` shows everything it found โ your editor and platform included โ and asks once:
|
|
56
|
+
>
|
|
57
|
+
> ```
|
|
58
|
+
> โน Found 8 stacks: core, git, node, nuxt, tauri, dotenv, vscode, linux
|
|
59
|
+
> ? Use them? โบ Yes / No
|
|
60
|
+
> ```
|
|
61
|
+
>
|
|
62
|
+
> In CI it asks nothing โ `--yes` or no terminal takes the committed fingerprints alone, says what it skipped, and writes. Your platform must not end up in a committed header because a pipeline ran.
|
|
63
|
+
|
|
64
|
+
## โจ Features
|
|
65
|
+
|
|
66
|
+
- **๐ Re-syncs, never re-dumps** โ `sync` is idempotent, so it belongs in a habit, a hook or a cron, not in a one-off ritual.
|
|
67
|
+
- **๐ก๏ธ Your lines are never lost** โ a hand-written line found inside a managed block is *moved* to the free zone, not deleted. That rule is what makes the second run safe.
|
|
68
|
+
- **๐ Dedup that knows git** โ exact duplicates go; `.idea`, `.idea/`, `/.idea` and `.idea/*` are four different patterns to git, so they are **reported**, never silently merged.
|
|
69
|
+
- **๐งน Orphaned headings swept** โ when a managed block absorbs every pattern under a `# Comment`, the heading goes with them. A block that was only ever a note stays.
|
|
70
|
+
- **โ ๏ธ Catches the mistake that breaks `!`** โ a stray `.vscode` beside a `!.vscode/extensions.json` block silently disables it, because git never looks inside an ignored directory. That gets its own warning.
|
|
71
|
+
- **๐งญ No surprise rewrites** โ `init` detects, `sync` does not. Adding a `package.json` never quietly rewrites your `.gitignore`; `sync --detect` proposes and stops there.
|
|
72
|
+
- **๐๏ธ Folds in your editor** โ the region uses `# region` / `# endregion`, so VSCode collapses a 40-line managed block to a single line, at both nesting levels.
|
|
73
|
+
- **๐ A real CI gate** โ `check` reports drift and duplicates and exits non-zero, so a stale block fails the build instead of rotting.
|
|
74
|
+
|
|
75
|
+
## ๐๏ธ The shape
|
|
76
|
+
|
|
77
|
+
```gitignore
|
|
78
|
+
# region gitignore-sync
|
|
79
|
+
# stacks: core, node, vscode, intellij
|
|
80
|
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
81
|
+
|
|
82
|
+
# region core@v1
|
|
83
|
+
.DS_Store
|
|
84
|
+
.claude/settings.local.json
|
|
85
|
+
# endregion
|
|
86
|
+
|
|
87
|
+
# region node@v1
|
|
88
|
+
node_modules
|
|
89
|
+
dist
|
|
90
|
+
coverage
|
|
91
|
+
# endregion
|
|
92
|
+
|
|
93
|
+
# endregion
|
|
94
|
+
|
|
95
|
+
# โโโ your rules, never touched โโโ
|
|
96
|
+
frankenphp
|
|
97
|
+
/bootstrap/ssr
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Everything below the closing `# endregion` is the **free zone**: yours, preserved line for line.
|
|
101
|
+
|
|
102
|
+
## ๐งฉ Stacks
|
|
103
|
+
|
|
104
|
+
Twenty curated blocks, each derived from what the estate actually ignores rather than from a public template site.
|
|
105
|
+
|
|
106
|
+
| Stack | What it covers | Proposed by `init` when |
|
|
107
|
+
| :--------- | :----------------------------------- | :---------------------------- |
|
|
108
|
+
| `core` | `.DS_Store`, agent-local settings | always |
|
|
109
|
+
| `git` | merge and backup droppings | always (it is a git repo) |
|
|
110
|
+
| `node` | modules, build output, logs, caches | `package.json` |
|
|
111
|
+
| `dotenv` | `.env*`, minus the committed example | `.env.example` or `.env` |
|
|
112
|
+
| `php` | `/vendor`, PHPUnit caches | `composer.json` |
|
|
113
|
+
| `laravel` | build output, storage keys, SSR | `artisan` |
|
|
114
|
+
| `go` | test and build droppings | `go.mod` |
|
|
115
|
+
| `tofu` | state, tfvars, local overrides | `*.tf` / `*.tofu` |
|
|
116
|
+
| `nuxt` | `.nuxt`, `.output`, `.nitro` | `nuxt.config.*` |
|
|
117
|
+
| `tauri` | `src-tauri/target`, generated schemas| `src-tauri/` |
|
|
118
|
+
| `rust` | `/target` | a root `Cargo.toml` |
|
|
119
|
+
| `turborepo`| `.turbo` | `turbo.json` |
|
|
120
|
+
| `playwright` | test-results, reports | `playwright.config.*` |
|
|
121
|
+
| `storybook`| `storybook-static` | `.storybook/` |
|
|
122
|
+
| `vscode` | `.vscode/*` + the shared files | you have a `.vscode/` |
|
|
123
|
+
| `intellij` | `.idea/*` | you have a `.idea/` |
|
|
124
|
+
| `vim` | swap and session files | your `$EDITOR` is vim |
|
|
125
|
+
| `macos` | AppleDouble, Spotlight, Trashes | you are on a Mac |
|
|
126
|
+
| `windows` | Thumbs.db, desktop.ini, Recycle Bin | you are on Windows |
|
|
127
|
+
| `linux` | `*~`, trash and NFS droppings | you are on Linux |
|
|
128
|
+
|
|
129
|
+
`gitignore-sync list` prints this for the binary you have installed, marking the ones your repo declares.
|
|
130
|
+
|
|
131
|
+
## โ๏ธ Configuration
|
|
132
|
+
|
|
133
|
+
There is no config file. The configuration is the `# stacks:` line in the `.gitignore` itself โ the header is **input**, the blocks below it are **output**.
|
|
134
|
+
|
|
135
|
+
| Edit | Effect after `sync` |
|
|
136
|
+
| :-------------------------------- | :--------------------------------------------- |
|
|
137
|
+
| Add a name to `# stacks:` | Its block is rendered into the region |
|
|
138
|
+
| Remove a name from `# stacks:` | Its block disappears; your own lines are kept |
|
|
139
|
+
| Nothing | Nothing โ `sync` is a no-op on a synced file |
|
|
140
|
+
|
|
141
|
+
> [!IMPORTANT]
|
|
142
|
+
> Nothing in a repository can tell you what the **other** contributors use โ `.vscode/` and `.idea/` are themselves ignored. So those stacks are proposed from your own machine and written down once, rather than re-guessed on every run. Only repository fingerprints reach the non-interactive path; a CI runner's platform must not end up in a committed header.
|
|
143
|
+
|
|
144
|
+
## ๐งช Use in CI
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
- run: npx @kirchdev/gitignore-sync check
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`check` writes nothing. It exits non-zero when the file has drifted from its header, and prints what it would have changed.
|
|
151
|
+
|
|
152
|
+
There is also an action, for a job summary on failure and a `status` output:
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
- uses: kirchDev/gitignore-sync@v0.1.0
|
|
156
|
+
with:
|
|
157
|
+
version: '0.1.0' # pin it, so a release cannot turn a green pipeline red
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
> [!TIP]
|
|
161
|
+
> Repos whose CI derives its task list from `package.json` need neither โ add
|
|
162
|
+
> `gitignore-sync check` to your `check` script and it comes along.
|
|
163
|
+
|
|
164
|
+
## ๐ค Contributing
|
|
165
|
+
|
|
166
|
+
PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs the project's linters/formatters on `git commit`.
|
|
167
|
+
|
|
168
|
+
> [!TIP]
|
|
169
|
+
> Run `pnpm check:fix` before pushing โ CI will catch what husky missed.
|
|
170
|
+
|
|
171
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow.
|
|
172
|
+
|
|
173
|
+
## ๐ฃ๏ธ Versioning
|
|
174
|
+
|
|
175
|
+
[Semantic Versioning](https://semver.org/) via [release-please](https://github.com/googleapis/release-please) โ see [CHANGELOG.md](CHANGELOG.md).
|
|
176
|
+
|
|
177
|
+
## ๐ License
|
|
178
|
+
|
|
179
|
+
[MIT](LICENSE) ยฉ [Titus Kirch](https://github.com/TitusKirch/) / [IT-Dienstleistungen Titus Kirch](https://kirch.dev)
|
package/action.yml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: 'gitignore-sync'
|
|
2
|
+
description: 'Check that a repository .gitignore still matches the stacks its header declares.'
|
|
3
|
+
author: 'Titus Kirch'
|
|
4
|
+
|
|
5
|
+
branding:
|
|
6
|
+
icon: 'git-branch'
|
|
7
|
+
color: 'green'
|
|
8
|
+
|
|
9
|
+
inputs:
|
|
10
|
+
directory:
|
|
11
|
+
description: 'Repository directory holding the .gitignore to check.'
|
|
12
|
+
required: false
|
|
13
|
+
default: '.'
|
|
14
|
+
version:
|
|
15
|
+
description: >-
|
|
16
|
+
Version of @kirchdev/gitignore-sync to run. Pin it so a new release cannot turn a
|
|
17
|
+
green pipeline red on its own.
|
|
18
|
+
required: false
|
|
19
|
+
default: 'latest'
|
|
20
|
+
node-version:
|
|
21
|
+
description: 'Node version used to run the CLI.'
|
|
22
|
+
required: false
|
|
23
|
+
default: '24'
|
|
24
|
+
|
|
25
|
+
outputs:
|
|
26
|
+
status:
|
|
27
|
+
description: '"in-sync" or "drifted".'
|
|
28
|
+
value: ${{ steps.check.outputs.status }}
|
|
29
|
+
|
|
30
|
+
# A composite action rather than a bundled JavaScript one: this wraps a single
|
|
31
|
+
# published CLI whose exit code is the whole result. Bundling the tool into
|
|
32
|
+
# dist/index.js would mean shipping the same code twice and keeping the two in
|
|
33
|
+
# step โ see kirchDev/coverage-report for the case where bundling does earn its
|
|
34
|
+
# keep, because that action writes comments and check runs of its own.
|
|
35
|
+
runs:
|
|
36
|
+
using: 'composite'
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/setup-node@v7
|
|
39
|
+
with:
|
|
40
|
+
node-version: ${{ inputs.node-version }}
|
|
41
|
+
|
|
42
|
+
- id: check
|
|
43
|
+
shell: bash
|
|
44
|
+
env:
|
|
45
|
+
GIS_DIR: ${{ inputs.directory }}
|
|
46
|
+
GIS_VERSION: ${{ inputs.version }}
|
|
47
|
+
run: |
|
|
48
|
+
set -o pipefail
|
|
49
|
+
if npx --yes "@kirchdev/gitignore-sync@${GIS_VERSION}" check "${GIS_DIR}" 2>&1 | tee "${RUNNER_TEMP}/gitignore-sync.log"; then
|
|
50
|
+
echo 'status=in-sync' >> "${GITHUB_OUTPUT}"
|
|
51
|
+
else
|
|
52
|
+
echo 'status=drifted' >> "${GITHUB_OUTPUT}"
|
|
53
|
+
{
|
|
54
|
+
echo '### `.gitignore` is out of sync'
|
|
55
|
+
echo
|
|
56
|
+
echo 'Run `gitignore-sync sync` and commit the result.'
|
|
57
|
+
echo
|
|
58
|
+
echo '```'
|
|
59
|
+
cat "${RUNNER_TEMP}/gitignore-sync.log"
|
|
60
|
+
echo '```'
|
|
61
|
+
} >> "${GITHUB_STEP_SUMMARY}"
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|