boilersync 0.1.1__tar.gz

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.
Files changed (36) hide show
  1. boilersync-0.1.1/.cursor/rules/adding-commands.mdc +25 -0
  2. boilersync-0.1.1/.cursor/rules/project-description.mdc +6 -0
  3. boilersync-0.1.1/.cursor/rules/python-conventions.mdc +8 -0
  4. boilersync-0.1.1/.github/workflows/publish.yml +78 -0
  5. boilersync-0.1.1/.gitignore +186 -0
  6. boilersync-0.1.1/.vscode/launch.json +35 -0
  7. boilersync-0.1.1/.vscode/settings.json +17 -0
  8. boilersync-0.1.1/.vscode/tasks.json +20 -0
  9. boilersync-0.1.1/PKG-INFO +232 -0
  10. boilersync-0.1.1/README.md +206 -0
  11. boilersync-0.1.1/boilersync/__init__.py +1 -0
  12. boilersync-0.1.1/boilersync/__main__.py +4 -0
  13. boilersync-0.1.1/boilersync/_version.py +21 -0
  14. boilersync-0.1.1/boilersync/cli.py +38 -0
  15. boilersync-0.1.1/boilersync/cli_helpers.py +68 -0
  16. boilersync-0.1.1/boilersync/commands/__init__.py +0 -0
  17. boilersync-0.1.1/boilersync/commands/init.py +41 -0
  18. boilersync-0.1.1/boilersync/commands/pull.py +477 -0
  19. boilersync-0.1.1/boilersync/commands/push.py +544 -0
  20. boilersync-0.1.1/boilersync/errors.py +0 -0
  21. boilersync-0.1.1/boilersync/interpolation_context.py +136 -0
  22. boilersync-0.1.1/boilersync/logging.py +32 -0
  23. boilersync-0.1.1/boilersync/names.py +98 -0
  24. boilersync-0.1.1/boilersync/paths.py +160 -0
  25. boilersync-0.1.1/boilersync/template_processor.py +203 -0
  26. boilersync-0.1.1/boilersync/user_settings.py +130 -0
  27. boilersync-0.1.1/boilersync/variable_collector.py +136 -0
  28. boilersync-0.1.1/pyproject.toml +60 -0
  29. boilersync-0.1.1/scripts/build.sh +38 -0
  30. boilersync-0.1.1/tests/__init__.py +0 -0
  31. boilersync-0.1.1/tests/test_filename_interpolation.py +67 -0
  32. boilersync-0.1.1/tests/test_template_inheritance.py +144 -0
  33. boilersync-0.1.1/tests/test_user_settings.py +169 -0
  34. boilersync-0.1.1/tests/test_variable_collection.py +160 -0
  35. boilersync-0.1.1/tests/test_variable_collection_integration.py +239 -0
  36. boilersync-0.1.1/tests/test_variable_type_conversion.py +80 -0
@@ -0,0 +1,25 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ Add commands to the `commands` dir. To define a command, name the python file after the command, e.g. `my_function.py`, and declare it with e.g.:
7
+
8
+ ```python
9
+ def my_function(argument1: str) -> None:
10
+ ...logic here...
11
+
12
+
13
+ @click.command(name="my-function")
14
+ @click.argument("argument1")
15
+ def my_function_cmd(argument1: str):
16
+ """Documentation goes here
17
+ """
18
+ my_function(argument1)
19
+ ```
20
+
21
+ Then register it in `cli.py` with e.g.:
22
+
23
+ ```python
24
+ main.add_command(common_command_wrapper(my_function_cmd))
25
+ ```
@@ -0,0 +1,6 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ `boilersync` is a boilerplate CLI tool that can not only generate projects from boilerplate templates, but keep the boilerplate "alive" and updated as you continue to develop the derivative projects.
@@ -0,0 +1,8 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ Only use `try` and `except` when you are truly implementing recovery-from-failure logic.
7
+ Prefer `pathlib` over `os` operations for dealing with files/paths.
8
+ Prefer `logger` calls over `print`.
@@ -0,0 +1,78 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*" # Only runs on version tags like v1.0.0
7
+
8
+ jobs:
9
+ publish-pypi:
10
+ runs-on: ubuntu-latest
11
+ permissions: write-all
12
+ steps:
13
+ - name: Check out code
14
+ uses: actions/checkout@v3
15
+ with:
16
+ fetch-depth: 0
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v4
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ - name: Install build tools
24
+ run: pip install build twine hatch
25
+
26
+ - name: Build PyPI package
27
+ run: hatch build
28
+
29
+ - name: Publish to PyPI
30
+ env:
31
+ TWINE_USERNAME: __token__
32
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
33
+ run: twine upload dist/*
34
+
35
+ build-homebrew:
36
+ runs-on: macos-latest
37
+ permissions: write-all
38
+ steps:
39
+ - name: Check out code
40
+ uses: actions/checkout@v3
41
+
42
+ - name: Set up Python
43
+ uses: actions/setup-python@v4
44
+ with:
45
+ python-version: "3.11"
46
+
47
+ - name: Install build tools
48
+ run: pip install pyinstaller
49
+
50
+ - name: Run PyInstaller build script
51
+ run: bash scripts/build.sh
52
+
53
+ - name: Create binary tarball
54
+ run: tar -czf boilersync.tar.gz -C dist/boilersync .
55
+
56
+ - name: Upload binary artifact
57
+ uses: actions/upload-artifact@v4
58
+ with:
59
+ name: boilersync-binary
60
+ path: boilersync.tar.gz
61
+ retention-days: 5
62
+
63
+ - name: Upload to Release
64
+ if: startsWith(github.ref, 'refs/tags/')
65
+ uses: softprops/action-gh-release@v1
66
+ with:
67
+ files: boilersync.tar.gz
68
+
69
+ - name: Update Homebrew formula
70
+ uses: dawidd6/action-homebrew-bump-formula@v4
71
+ with:
72
+ token: ${{secrets.GH_TOKEN}}
73
+ # Optional, use the origin repository instead of forking
74
+ no_fork: true
75
+ # Optional, defaults to homebrew/core
76
+ tap: montaguegabe/homebrew-boilersync
77
+ # Formula name, required
78
+ formula: boilersync
@@ -0,0 +1,186 @@
1
+ .data/
2
+
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ # Usually these files are written by a python script from a template
33
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
34
+ *.manifest
35
+ *.spec
36
+
37
+ # Installer logs
38
+ pip-log.txt
39
+ pip-delete-this-directory.txt
40
+
41
+ # Unit test / coverage reports
42
+ htmlcov/
43
+ .tox/
44
+ .nox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ *.py,cover
52
+ .hypothesis/
53
+ .pytest_cache/
54
+ cover/
55
+
56
+ # Translations
57
+ *.mo
58
+ *.pot
59
+
60
+ # Django stuff:
61
+ *.log
62
+ local_settings.py
63
+ db.sqlite3
64
+ db.sqlite3-journal
65
+
66
+ # Flask stuff:
67
+ instance/
68
+ .webassets-cache
69
+
70
+ # Scrapy stuff:
71
+ .scrapy
72
+
73
+ # Sphinx documentation
74
+ docs/_build/
75
+
76
+ # PyBuilder
77
+ .pybuilder/
78
+ target/
79
+
80
+ # Jupyter Notebook
81
+ .ipynb_checkpoints
82
+
83
+ # IPython
84
+ profile_default/
85
+ ipython_config.py
86
+
87
+ # pyenv
88
+ # For a library or package, you might want to ignore these files since the code is
89
+ # intended to run in multiple environments; otherwise, check them in:
90
+ # .python-version
91
+
92
+ # pipenv
93
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
95
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
96
+ # install all needed dependencies.
97
+ #Pipfile.lock
98
+
99
+ # poetry
100
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
101
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
102
+ # commonly ignored for libraries.
103
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
104
+ #poetry.lock
105
+
106
+ # pdm
107
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
108
+ #pdm.lock
109
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
110
+ # in version control.
111
+ # https://pdm.fming.dev/#use-with-ide
112
+ .pdm.toml
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .env.gha
127
+ .venv
128
+ env/
129
+ venv/
130
+ ENV/
131
+ env.bak/
132
+ venv.bak/
133
+
134
+ # Spyder project settings
135
+ .spyderproject
136
+ .spyproject
137
+
138
+ # Rope project settings
139
+ .ropeproject
140
+
141
+ # mkdocs documentation
142
+ /site
143
+
144
+ # mypy
145
+ .mypy_cache/
146
+ .dmypy.json
147
+ dmypy.json
148
+
149
+ # Pyre type checker
150
+ .pyre/
151
+
152
+ # pytype static type analyzer
153
+ .pytype/
154
+
155
+ # Cython debug symbols
156
+ cython_debug/
157
+
158
+ # Ruff stuff:
159
+ .ruff_cache/
160
+
161
+ # PyPI configuration file
162
+ .pypirc
163
+
164
+ # Virtual Environment
165
+ .env
166
+ .venv
167
+ env/
168
+ venv/
169
+ ENV/
170
+
171
+ # IDE
172
+ .idea/
173
+ # .vscode/
174
+ *.swp
175
+ *.swo
176
+
177
+ # OS
178
+ .DS_Store
179
+ Thumbs.db
180
+
181
+ staticfiles
182
+
183
+ .env
184
+ _version.py
185
+
186
+ playground/
@@ -0,0 +1,35 @@
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "name": "Pytest",
6
+ "type": "debugpy",
7
+ "request": "launch",
8
+ "module": "pytest",
9
+ "args": [
10
+ "tests",
11
+ "-q",
12
+ "--tb=native",
13
+ "-s",
14
+ "-x"
15
+ ],
16
+ "console": "integratedTerminal",
17
+ "justMyCode": false,
18
+ "env": {
19
+ "PYTEST_ADDOPTS": "--no-cov"
20
+ }
21
+ },
22
+ {
23
+ "name": "Boilersync (zebra-crossing)",
24
+ "type": "debugpy",
25
+ "request": "launch",
26
+ "module": "boilersync",
27
+ "args": [
28
+ "push"
29
+ ],
30
+ "console": "integratedTerminal",
31
+ "justMyCode": false,
32
+ "cwd": "${workspaceFolder}/playground/zebra-crossing"
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "python.testing.pytestArgs": [
3
+ ".",
4
+ "--no-cov",
5
+ "-q",
6
+ "--tb=native",
7
+ "-s",
8
+ "-x"
9
+ ],
10
+ "python.testing.unittestEnabled": false,
11
+ "python.testing.pytestEnabled": true,
12
+ "python.experiments.optInto": [
13
+ "pythonTestAdapter"
14
+ ],
15
+ "python.experiments.enabled": true,
16
+ "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python"
17
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "Run pytest with coverage",
6
+ "type": "shell",
7
+ "command": "${workspaceFolder}/venv/bin/pytest . --cov=boilersync --cov-report=html && open htmlcov/index.html",
8
+ "group": {
9
+ "kind": "test",
10
+ "isDefault": true
11
+ },
12
+ "presentation": {
13
+ "reveal": "always",
14
+ "panel": "new",
15
+ "close": true
16
+ },
17
+ "problemMatcher": []
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: boilersync
3
+ Version: 0.1.1
4
+ Summary: BoilerSync
5
+ Project-URL: Repository, https://github.com/gabemontague/boilersync
6
+ Project-URL: Issues, https://github.com/gabemontague/boilersync/issues
7
+ Author-email: Gabe Montague <gabemontague@outlook.com>
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Topic :: Software Development :: Version Control :: Git
15
+ Requires-Python: >=3.9
16
+ Requires-Dist: click>=8.2.0
17
+ Requires-Dist: gitpython>=3.1.44
18
+ Requires-Dist: jinja2>=3.1.6
19
+ Provides-Extra: dev
20
+ Requires-Dist: pyinstaller>=6.9.0; extra == 'dev'
21
+ Requires-Dist: pytest-cov>=6.1.1; extra == 'dev'
22
+ Requires-Dist: pytest-mock>=3.14.0; extra == 'dev'
23
+ Requires-Dist: pytest>=8.3.5; extra == 'dev'
24
+ Requires-Dist: ruff>=0.11.10; extra == 'dev'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # boilersync
28
+
29
+ `boilersync` is a boilerplate CLI tool that can not only generate projects from boilerplate templates, but keep the boilerplate "alive" and updated as you continue to develop the derivative projects.
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ # Initialize a new project from a template
35
+ boilersync init my-template-name
36
+
37
+ # Show pusherences between your project and the original template
38
+ boilersync push
39
+ ```
40
+
41
+ When you run the init command, you'll be prompted for project details:
42
+
43
+ ```bash
44
+ $ boilersync init my-web-app
45
+
46
+ 🚀 Initializing project from template 'my-web-app'
47
+ ==================================================
48
+ Project name (snake_case) [my_awesome_project]: my_cool_app
49
+ Pretty name for display [My Cool App]: My Cool Application
50
+ ==================================================
51
+ ```
52
+
53
+ ## Template System
54
+
55
+ ### Project Name Variables
56
+
57
+ When initializing a project, `boilersync` prompts you for a snake_case project name and a pretty display name, then generates variables in pusherent naming conventions:
58
+
59
+ **For file/folder names (uppercase, no special symbols):**
60
+
61
+ - `NAME_SNAKE`: `my_awesome_project`
62
+ - `NAME_PASCAL`: `MyAwesomeProject`
63
+ - `NAME_KEBAB`: `my-awesome-project`
64
+ - `NAME_CAMEL`: `myAwesomeProject`
65
+ - `NAME_PRETTY`: `My Awesome Project`
66
+
67
+ **For file contents (lowercase, used with Jinja2 delimiters):**
68
+
69
+ - `name_snake`: `my_awesome_project`
70
+ - `name_pascal`: `MyAwesomeProject`
71
+ - `name_kebab`: `my-awesome-project`
72
+ - `name_camel`: `myAwesomeProject`
73
+ - `name_pretty`: `My Awesome Project`
74
+
75
+ ### File and Folder Name Interpolation
76
+
77
+ Use the naming variables directly in file and folder names:
78
+
79
+ ```
80
+ src/NAME_SNAKE_service.py → src/my_awesome_project_service.py
81
+ docs/NAME_KEBAB-guide.md → docs/my-awesome-project-guide.md
82
+ NAME_PASCAL/ → MyAwesomeProject/
83
+ ```
84
+
85
+ ### Template Content Processing
86
+
87
+ Template files use custom Jinja2 delimiters to avoid conflicts:
88
+
89
+ - **Variables**: `$${variable_name}`
90
+ - **Blocks**: `$${% if condition %}...$${% endif %}`
91
+ - **Comments**: `$${# This is a comment #}`
92
+
93
+ Example template file:
94
+
95
+ ```python
96
+ class $${name_pascal}Service:
97
+ def __init__(self):
98
+ self.name = "$${name_snake}"
99
+ self.kebab_name = "$${name_kebab}"
100
+
101
+ $${# This comment will be removed #}
102
+ $${% if include_logging %}
103
+ import logging
104
+ $${% endif %}
105
+ ```
106
+
107
+ ### Interactive Variable Collection
108
+
109
+ When initializing a template, `boilersync` automatically scans template files (`.boilersync` files) for variables used in Jinja2 syntax. If it finds variables that aren't predefined (like the project name variables), it will prompt you to provide values:
110
+
111
+ ```bash
112
+ $ boilersync init my-web-app
113
+
114
+ 🔧 Additional variables needed for this template:
115
+ ==================================================
116
+ Enter value for 'author_email' (email address): user@example.com
117
+ Enter value 'author_name' (name): John Doe
118
+ Enter value for 'api_version' (version number): v1.0
119
+ Enter value for 'database_url' (URL): postgresql://localhost:5432/mydb
120
+ ==================================================
121
+ ✅ All variables collected!
122
+ ```
123
+
124
+ The system provides helpful prompts based on variable name patterns:
125
+
126
+ - Variables ending in `_email` → prompts for "email address"
127
+ - Variables ending in `_name` → prompts for "name"
128
+ - Variables ending in `_url` → prompts for "URL"
129
+ - Variables ending in `_version` → prompts for "version number"
130
+ - Variables ending in `_description` → prompts for "description"
131
+
132
+ Once collected, these values are remembered and reused if the same variable appears in multiple files.
133
+
134
+ ## Project Tracking
135
+
136
+ After initialization, `boilersync` creates a `.boilersync` file in your project root to track the template and project information:
137
+
138
+ ```json
139
+ {
140
+ "template": "web-app",
141
+ "name_snake": "my_awesome_project",
142
+ "name_pretty": "My Awesome Project"
143
+ }
144
+ ```
145
+
146
+ This file uses the same variable names that templates reference, making it easy to understand and potentially use in other tools.
147
+
148
+ ## Push Command
149
+
150
+ The `push` command helps you see how your project has diverged from its original template. This is useful for:
151
+
152
+ - Understanding what changes you've made
153
+ - Deciding what to sync when templates are updated
154
+ - Reviewing project evolution
155
+
156
+ ### How It Works
157
+
158
+ 1. **Finds your project root**: Locates the nearest `.boilersync` file (created during `init`)
159
+ 2. **Reads project info**: Gets the original template name and project names from `.boilersync`
160
+ 3. **Creates fresh template**: Initializes the template in a temporary directory using saved names
161
+ 4. **Sets up git**: Creates a git repo and commits the fresh template
162
+ 5. **Overlays your changes**: Copies your current project files over the fresh template
163
+ 6. **Opens push viewer**: Launches GitHub Desktop to show the pusherences
164
+
165
+ ### Usage
166
+
167
+ ```bash
168
+ $ cd my-project
169
+ $ boilersync push
170
+
171
+ 🔍 Creating push for template 'web-app'...
172
+ 📦 Initializing fresh template in temporary directory...
173
+ 🚀 Initializing project from template 'web-app'
174
+ 📝 Using saved project name: my_project
175
+ 📝 Using saved pretty name: My Project
176
+ 🔧 Setting up git repository...
177
+ 📋 Copying current project files...
178
+ 🚀 Opening in GitHub Desktop...
179
+ 📂 Temporary directory created and opened in GitHub Desktop.
180
+ ⏳ Press Enter when you're done reviewing the push...
181
+ ```
182
+
183
+ The push will show:
184
+
185
+ - **Green (additions)**: Your custom changes and new files
186
+ - **Red (deletions)**: Template parts you've removed or modified
187
+ - **Modified files**: Side-by-side comparison of your changes vs template
188
+
189
+ ### Special File Extensions
190
+
191
+ #### `.boilersync` Extension
192
+
193
+ Files ending with `.boilersync` are processed as templates and have the extension removed:
194
+
195
+ - `package.json.boilersync` → `package.json` (processed)
196
+ - `README.md.boilersync` → `README.md` (processed)
197
+ - `config.yaml` → `config.yaml` (copied as-is)
198
+
199
+ #### `.starter` Extension
200
+
201
+ Files with `.starter` as the first extension are "starter files" - they're used only during initialization and won't be synced in future updates:
202
+
203
+ - `example.starter.py` → `example.py` (init only, no future sync)
204
+ - `sample.starter.config.json` → `sample.config.json` (init only)
205
+ - `tutorial.starter.md.boilersync` → `tutorial.md` (processed + init only)
206
+
207
+ ### Template Directory Structure
208
+
209
+ ```
210
+ boilerplate/
211
+ ├── my-template/
212
+ │ ├── src/
213
+ │ │ ├── NAME_SNAKE_service.py.boilersync
214
+ │ │ └── utils.py
215
+ │ ├── docs/
216
+ │ │ ├── README.md.boilersync
217
+ │ │ └── getting-started.starter.md.boilersync
218
+ │ └── package.json.boilersync
219
+ ```
220
+
221
+ After `boilersync init my-template` in directory `MyAwesomeProject`:
222
+
223
+ ```
224
+ MyAwesomeProject/
225
+ ├── src/
226
+ │ ├── my_awesome_project_service.py
227
+ │ └── utils.py
228
+ ├── docs/
229
+ │ ├── README.md
230
+ │ └── getting-started.md
231
+ └── package.json
232
+ ```