dotsync 0.1.25 → 0.1.26

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 793ae0a7e00707a97255d631304eddae60e6ce6224d8c4d85c9550f54cbd59bd
4
- data.tar.gz: 34fdbefc7f9b27a2f7fedd8dcbac9748ae59c99fb7cb15a970ebc67605e5ebe1
3
+ metadata.gz: 89c25a6529e3557dc1383f3facf677f0775053d7db53863b7cc61a5b44d13b11
4
+ data.tar.gz: 1cfadbe1c539923fb6bf9c27eafde24beeab527feeaadf2b88d997d762f972b4
5
5
  SHA512:
6
- metadata.gz: 50471dd7fca75246adb01dd946b17dc217b590cc0df359253f608f4868ae190c08aeb5ce5c9302dafa2533f368c69f35b1f9b3f70143ed36066745729904030b
7
- data.tar.gz: 2061b3db4dfb07aaec4750efba675091797ce8ebcb9979ce37ffca5e1b838f20d2ebec181925c45d5a0a6c52d4681d05f989953f4022540c0a6705dc8fc6dd76
6
+ metadata.gz: 2b7012240c48cd7b9d84cf8e20d54efa913fd08324720b08d270db0c39e46f87a1f63f124e6d562d06ab2bef7f0fd017bb686e666b40866fc89eceae831de1bf
7
+ data.tar.gz: 87f03124b8dc8cad8c3588d3391858414ac0a577416c7a227465702a081c8de9fa36648e5eb5c642ba9b6beae81c19043259c25b536a634cd3bfcd3b83a7cfc9
@@ -1,4 +1,4 @@
1
- name: Ruby Gem
1
+ name: CI
2
2
 
3
3
  on:
4
4
  push:
@@ -0,0 +1,50 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout code
17
+ uses: actions/checkout@v6
18
+
19
+ - name: Get version from tag
20
+ id: version
21
+ run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
22
+
23
+ - name: Extract changelog for version
24
+ id: changelog
25
+ run: |
26
+ # Extract the section for this version from CHANGELOG.md
27
+ # Matches from "## [X.Y.Z]" until the next "## [" or end of file
28
+ VERSION="${{ steps.version.outputs.version }}"
29
+ CHANGELOG=$(awk -v ver="$VERSION" '
30
+ /^## \[/ {
31
+ if (found) exit
32
+ if ($0 ~ "\\[" ver "\\]") found=1
33
+ }
34
+ found { print }
35
+ ' CHANGELOG.md | tail -n +2)
36
+
37
+ # Use heredoc for multiline output
38
+ echo "content<<EOF" >> $GITHUB_OUTPUT
39
+ echo "$CHANGELOG" >> $GITHUB_OUTPUT
40
+ echo "EOF" >> $GITHUB_OUTPUT
41
+
42
+ - name: Create GitHub Release
43
+ uses: softprops/action-gh-release@v2
44
+ with:
45
+ name: v${{ steps.version.outputs.version }}
46
+ body: ${{ steps.changelog.outputs.content }}
47
+ draft: false
48
+ prerelease: false
49
+ env:
50
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ .claude/
@@ -0,0 +1,9 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: rubocop
5
+ name: rubocop
6
+ entry: bundle exec rubocop --autocorrect --force-exclusion
7
+ language: system
8
+ types: [ruby]
9
+ pass_filenames: true
data/CHANGELOG.md CHANGED
@@ -1,4 +1,36 @@
1
- # 0.1.25
1
+ ## [0.1.26] - 2025-01-11
2
+
3
+ **Breaking Changes:**
4
+ - The explicit sync mapping syntax has changed from `[[sync]]` to `[[sync.mappings]]`
5
+ - Old: `[[sync]]` with `local`/`remote` keys
6
+ - New: `[[sync.mappings]]` with `local`/`remote` keys
7
+ - This allows combining explicit mappings with XDG shorthands in the same config
8
+ - See README for migration examples
9
+
10
+ **New Features:**
11
+ - Add bidirectional `[[sync.mappings]]` DSL for two-way synchronization
12
+ - Simplified syntax replaces separate push/pull mappings
13
+ - Automatic expansion to bidirectional mappings (local ↔ remote)
14
+ - Supports all existing options: `force`, `only`, `ignore`
15
+ - Add XDG shorthand DSL for sync mappings
16
+ - `[[sync.home]]` - syncs $HOME ↔ $HOME_MIRROR
17
+ - `[[sync.xdg_config]]` - syncs $XDG_CONFIG_HOME ↔ $XDG_CONFIG_HOME_MIRROR
18
+ - `[[sync.xdg_data]]` - syncs $XDG_DATA_HOME ↔ $XDG_DATA_HOME_MIRROR
19
+ - `[[sync.xdg_cache]]` - syncs $XDG_CACHE_HOME ↔ $XDG_CACHE_HOME_MIRROR
20
+ - `[[sync.xdg_bin]]` - syncs $XDG_BIN_HOME ↔ $XDG_BIN_HOME_MIRROR (new)
21
+ - Use `path` for specific subdirectories or `only` for multiple paths
22
+ - Fix custom config path (`-c` flag) not being applied to Runner
23
+
24
+ **Documentation:**
25
+ - Document bidirectional sync mappings with examples
26
+ - Document XDG shorthand DSL with usage examples
27
+ - Update README with new configuration options and supported shorthands table
28
+
29
+ **Infrastructure:**
30
+ - Rename GitHub workflow to ci.yml
31
+ - Add sync_mappings concern to push and pull loaders
32
+
33
+ ## [0.1.25]
2
34
 
3
35
  **Features:**
4
36
  - Add support for file-specific paths in 'only' configuration option
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dotsync (0.1.25)
4
+ dotsync (0.1.26)
5
5
  fileutils (~> 1.7.3)
6
6
  find (~> 0.2.0)
7
7
  listen (~> 3.9.0)
data/README.md CHANGED
@@ -13,7 +13,8 @@
13
13
  Dotsync is a powerful Ruby gem for managing and synchronizing your dotfiles across machines. Whether you're setting up a new development environment or keeping configurations in sync, Dotsync makes it effortless.
14
14
 
15
15
  **Key Features:**
16
- - **Bidirectional Sync**: Push local dotfiles to your repository or pull from repository to local machine
16
+ - **Bidirectional Sync Mappings**: Define once, sync both ways eliminates config duplication with `[[sync.mappings]]` syntax
17
+ - **XDG Shorthand DSL**: Concise `[[sync.home]]`, `[[sync.xdg_config]]`, `[[sync.xdg_data]]`, `[[sync.xdg_bin]]` syntax for common directory patterns
17
18
  - **Preview Mode**: See what changes would be made before applying them (dry-run by default)
18
19
  - **Smart Filtering**: Use `force`, `only`, and `ignore` options to precisely control what gets synced
19
20
  - **Automatic Backups**: Pull operations create timestamped backups for easy recovery
@@ -29,6 +30,9 @@ Dotsync is a powerful Ruby gem for managing and synchronizing your dotfiles acro
29
30
  - [Usage](#usage)
30
31
  - [Executable Commands](#executable-commands)
31
32
  - [Configuration](#configuration)
33
+ - [Bidirectional Sync Mappings (Recommended)](#bidirectional-sync-mappings-recommended)
34
+ - [Alternative: Unidirectional Mappings](#alternative-unidirectional-mappings)
35
+ - [Mapping Options (force, only, ignore)](#force-only-and-ignore-options-in-mappings)
32
36
  - [Safety Features](#safety-features)
33
37
  - [Customizing Icons](#customizing-icons)
34
38
  - [Automatic Update Checks](#automatic-update-checks)
@@ -76,22 +80,29 @@ Get started with Dotsync in just a few steps:
76
80
  ```
77
81
  This creates `~/.config/dotsync.toml` with example mappings.
78
82
 
79
- 3. **Edit the configuration** (`~/.config/dotsync.toml`) to define your dotfile mappings:
83
+ 3. **Edit the configuration** (`~/.config/dotsync.toml`) to define your dotfile mappings using bidirectional sync:
80
84
  ```toml
81
- [[pull.mappings]]
82
- src = "$HOME/dotfiles/config"
83
- dest = "$HOME/.config"
85
+ # Sync your shell config
86
+ [[sync.home]]
87
+ path = ".zshenv"
88
+
89
+ # Sync XDG config directories
90
+ [[sync.xdg_config]]
91
+ only = ["nvim", "alacritty", "zsh", "git"]
92
+ force = true
84
93
  ```
85
94
 
86
95
  4. **Preview your changes** (dry-run mode):
87
96
  ```shell
88
- dotsync pull
97
+ dotsync pull # Preview pulling from repo to local
98
+ dotsync push # Preview pushing from local to repo
89
99
  ```
90
100
  This shows what would be changed without modifying any files.
91
101
 
92
102
  5. **Apply changes** when you're ready:
93
103
  ```shell
94
- dotsync pull --apply
104
+ dotsync pull --apply # Apply repo → local
105
+ dotsync push --apply # Apply local → repo
95
106
  ```
96
107
 
97
108
  ## Usage
@@ -127,7 +138,7 @@ Dotsync provides the following commands to manage your dotfiles:
127
138
  ```shell
128
139
  dotsync watch [OPTIONS]
129
140
  ```
130
-
141
+
131
142
  The watch command supports the same output control options as push and pull (e.g., `--quiet`, `--no-legend`, `--no-mappings`).
132
143
 
133
144
  - **Setup** (alias: **init**): Generate a default configuration file at `~/.config/dotsync.toml` with example mappings for `pull`, `push`, and `watch`.
@@ -212,53 +223,162 @@ dotsync watch --quiet # Watch with minimal output
212
223
 
213
224
  ### Configuration
214
225
 
215
- The configuration file uses a `mappings` structure to define the source and destination of your dotfiles. Here is an example:
226
+ Dotsync uses TOML configuration files to define mappings between your local machine and your dotfiles repository. The recommended approach is **bidirectional sync mappings**, which eliminate duplication and keep your config clean.
227
+
228
+ > [!TIP]
229
+ > Set up mirror environment variables for cleaner configuration:
230
+ > ```bash
231
+ > # Add to your ~/.zshrc or ~/.bashrc
232
+ > export DOTFILES_DIR="$HOME/Code/dotfiles"
233
+ > export XDG_CONFIG_HOME_MIRROR="$DOTFILES_DIR/xdg_config_home"
234
+ > export XDG_DATA_HOME_MIRROR="$DOTFILES_DIR/xdg_data_home"
235
+ > export HOME_MIRROR="$DOTFILES_DIR/home"
236
+ > ```
237
+
238
+ #### Bidirectional Sync Mappings (Recommended)
239
+
240
+ Use `[[sync]]` mappings to define paths that sync in both directions. This is the **preferred approach** as it eliminates duplication between push and pull configurations.
241
+
242
+ ##### XDG Shorthand Syntax
243
+
244
+ The most concise way to define mappings for standard XDG directories:
216
245
 
217
246
  ```toml
218
- [[pull.mappings]]
219
- src = "$XDG_CONFIG_HOME_MIRROR"
220
- dest = "$XDG_CONFIG_HOME"
221
- ignore = ["nvim"]
247
+ # Sync home directory files
248
+ [[sync.home]]
249
+ path = ".zshenv"
222
250
 
223
- [[pull.mappings]]
224
- src = "$XDG_CONFIG_HOME_MIRROR/nvim"
225
- dest = "$XDG_CONFIG_HOME/nvim"
226
- # FEATURE: forces the deletion of destination folder
251
+ # Sync multiple configs from XDG_CONFIG_HOME
252
+ [[sync.xdg_config]]
253
+ only = ["alacritty", "git", "zsh", "starship.toml"]
254
+ force = true
255
+
256
+ # Sync specific config with custom options
257
+ [[sync.xdg_config]]
258
+ path = "nvim"
227
259
  force = true
228
- # FEATURE: use relative paths to "dest" to ignore files and folders
229
260
  ignore = ["lazy-lock.json"]
230
261
 
231
- [[pull.mappings]]
232
- src = "$HOME_MIRROR/.zshenv"
233
- dest = "$HOME"
262
+ # Sync XDG data directories
263
+ [[sync.xdg_data]]
264
+ path = "git"
265
+ force = true
266
+ ```
234
267
 
268
+ **Supported shorthands:**
235
269
 
236
- [[push.mappings]]
237
- src = "$HOME/.zshenv"
238
- dest = "$HOME_MIRROR/.zshenv"
270
+ | Shorthand | Local | Remote |
271
+ |-----------|-------|--------|
272
+ | `sync.home` | `$HOME` | `$HOME_MIRROR` |
273
+ | `sync.xdg_config` | `$XDG_CONFIG_HOME` | `$XDG_CONFIG_HOME_MIRROR` |
274
+ | `sync.xdg_data` | `$XDG_DATA_HOME` | `$XDG_DATA_HOME_MIRROR` |
275
+ | `sync.xdg_cache` | `$XDG_CACHE_HOME` | `$XDG_CACHE_HOME_MIRROR` |
276
+ | `sync.xdg_bin` | `$XDG_BIN_HOME` | `$XDG_BIN_HOME_MIRROR` |
239
277
 
240
- [[push.mappings]]
241
- src = "$XDG_CONFIG_HOME/alacritty"
242
- dest = "$DOTFILES_DIR/config/alacritty"
243
- # FEATURE: transfer only relative paths of files and folders passed here
244
- only = ["alacritty.toml", "rose-pine.toml"]
278
+ **Options:**
279
+ - `path` (optional): Relative path within the directory. If omitted, syncs the entire directory.
280
+ - `force`, `ignore`, `only`: All standard mapping options are supported.
245
281
 
282
+ ##### Explicit Sync Syntax
246
283
 
247
- [[watch.mappings]]
248
- src = "$HOME/.zshenv"
249
- dest = "$HOME_MIRROR/.zshenv"
284
+ For custom paths that don't follow XDG conventions, use explicit `[[sync.mappings]]` entries:
285
+
286
+ ```toml
287
+ [[sync.mappings]]
288
+ local = "$XDG_CONFIG_HOME/nvim"
289
+ remote = "$XDG_CONFIG_HOME_MIRROR/nvim"
290
+ force = true
291
+ ignore = ["lazy-lock.json"]
292
+
293
+ [[sync.mappings]]
294
+ local = "$HOME/.zshenv"
295
+ remote = "$HOME_MIRROR/.zshenv"
296
+
297
+ # Sync config file to a different location in repo
298
+ [[sync.mappings]]
299
+ local = "$XDG_CONFIG_HOME/dotsync.toml"
300
+ remote = "$XDG_CONFIG_HOME_MIRROR/dotsync/dotsync.macbook.toml"
301
+ ```
302
+
303
+ **How it works:**
304
+ - `local` is your local machine path (e.g., `~/.config/nvim`)
305
+ - `remote` is your dotfiles repository path (e.g., `~/dotfiles/config/nvim`)
306
+ - For **push** operations: `local` → `remote`
307
+ - For **pull** operations: `remote` → `local`
308
+ - All standard options (`force`, `ignore`, `only`) are supported
309
+
310
+ ##### Complete Example
311
+
312
+ Here's a real-world configuration using bidirectional sync:
313
+
314
+ ```toml
315
+ ## BIDIRECTIONAL SYNC CONFIGURATION
316
+
317
+ # Home directory files
318
+ [[sync.home]]
319
+ path = ".zshenv"
320
+
321
+ # Bulk sync multiple configs
322
+ [[sync.xdg_config]]
323
+ only = [
324
+ "alacritty",
325
+ "brewfile",
326
+ "git",
327
+ "lazygit",
328
+ "tmux",
329
+ "zellij",
330
+ "starship.toml"
331
+ ]
332
+ force = true
333
+
334
+ # Zsh with ignored files
335
+ [[sync.xdg_config]]
336
+ path = "zsh"
337
+ ignore = [".zsh_sessions", ".zsh_history", ".zcompdump"]
338
+
339
+ # Neovim with force sync
340
+ [[sync.xdg_config]]
341
+ path = "nvim"
342
+ force = true
343
+ ignore = ["lazy-lock.json"]
344
+
345
+ # Git templates in data directory
346
+ [[sync.xdg_data]]
347
+ path = "git"
348
+ force = true
349
+
350
+ # This config file itself
351
+ [[sync.mappings]]
352
+ local = "$XDG_CONFIG_HOME/dotsync.toml"
353
+ remote = "$XDG_CONFIG_HOME_MIRROR/dotsync/dotsync.macbook.toml"
354
+ ```
355
+
356
+ #### Alternative: Unidirectional Mappings
357
+
358
+ For asymmetric sync scenarios where push and pull need different configurations, you can use separate `[[push.mappings]]` and `[[pull.mappings]]` sections:
250
359
 
360
+ ```toml
361
+ # Pull from repo to local (repo → local)
362
+ [[pull.mappings]]
363
+ src = "$XDG_CONFIG_HOME_MIRROR/nvim"
364
+ dest = "$XDG_CONFIG_HOME/nvim"
365
+ force = true
366
+ ignore = ["lazy-lock.json"]
367
+
368
+ # Push from local to repo (local → repo)
369
+ [[push.mappings]]
370
+ src = "$XDG_CONFIG_HOME/alacritty"
371
+ dest = "$XDG_CONFIG_HOME_MIRROR/alacritty"
372
+ only = ["alacritty.toml", "themes"]
373
+
374
+ # Watch for live syncing
251
375
  [[watch.mappings]]
252
- src = "$XDG_CONFIG_HOME/alacritty"
253
- dest = "$DOTFILES_DIR/config/alacritty"
376
+ src = "$XDG_CONFIG_HOME/nvim"
377
+ dest = "$XDG_CONFIG_HOME_MIRROR/nvim"
254
378
  ```
255
379
 
256
- > [!TIP]
257
- > I use mirror environment variables to cleaner configuration
258
- >
259
- > ```bash
260
- > export XDG_CONFIG_HOME_MIRROR="$HOME/Code/dotfiles/xdg_config_home"
261
- > ```
380
+ > [!NOTE]
381
+ > You can mix `[[sync.mappings]]`, XDG shorthands (`[[sync.home]]`, `[[sync.xdg_config]]`, etc.), and `[[push.mappings]]`/`[[pull.mappings]]` in the same config file. Use bidirectional sync for symmetric mappings and unidirectional for special cases.
262
382
 
263
383
  #### `force`, `only`, and `ignore` Options in Mappings
264
384
 
@@ -270,9 +390,8 @@ A boolean (true/false) value. When set to `true`, it forces deletion of files in
270
390
 
271
391
  **Example:**
272
392
  ```toml
273
- [[pull.mappings]]
274
- src = "$XDG_CONFIG_HOME_MIRROR/nvim"
275
- dest = "$XDG_CONFIG_HOME/nvim"
393
+ [[sync.xdg_config]]
394
+ path = "nvim"
276
395
  force = true
277
396
  ignore = ["lazy-lock.json"]
278
397
  ```
@@ -293,41 +412,34 @@ An array of relative paths (files or directories) to selectively transfer from t
293
412
 
294
413
  **Example 1: Selecting specific directories**
295
414
  ```toml
296
- [[push.mappings]]
297
- src = "$XDG_CONFIG_HOME"
298
- dest = "$DOTFILES_DIR/config"
415
+ [[sync.xdg_config]]
299
416
  only = ["nvim", "alacritty", "zsh"]
300
417
  ```
301
418
  This transfers only the `nvim/`, `alacritty/`, and `zsh/` directories.
302
419
 
303
420
  **Example 2: Selecting specific files**
304
421
  ```toml
305
- [[push.mappings]]
306
- src = "$XDG_CONFIG_HOME/alacritty"
307
- dest = "$DOTFILES_DIR/config/alacritty"
422
+ [[sync.xdg_config]]
423
+ path = "alacritty"
308
424
  only = ["alacritty.toml", "rose-pine.toml"]
309
425
  ```
310
426
  This transfers only two specific TOML files from the alacritty config directory.
311
427
 
312
428
  **Example 3: Selecting files inside nested directories**
313
429
  ```toml
314
- [[push.mappings]]
315
- src = "$HOME/.config"
316
- dest = "$DOTFILES_DIR/config"
430
+ [[sync.xdg_config]]
317
431
  only = ["bundle/config", "ghc/ghci.conf", "cabal/config"]
318
432
  ```
319
433
  This transfers only specific configuration files from different subdirectories:
320
434
  - `bundle/config` file from the `bundle/` directory
321
- - `ghc/ghci.conf` file from the `ghc/` directory
435
+ - `ghc/ghci.conf` file from the `ghc/` directory
322
436
  - `cabal/config` file from the `cabal/` directory
323
437
 
324
438
  The parent directories (`bundle/`, `ghc/`, `cabal/`) are created automatically in the destination, but other files in those directories are not transferred.
325
439
 
326
440
  **Example 4: Deeply nested paths**
327
441
  ```toml
328
- [[push.mappings]]
329
- src = "$XDG_CONFIG_HOME"
330
- dest = "$DOTFILES_DIR/config"
442
+ [[sync.xdg_config]]
331
443
  only = ["nvim/lua/plugins/init.lua", "nvim/lua/config/settings.lua"]
332
444
  ```
333
445
  This transfers only specific Lua files from deeply nested paths within the nvim configuration.
@@ -343,17 +455,15 @@ An array of relative paths or patterns to exclude during transfer. This allows y
343
455
 
344
456
  **Example:**
345
457
  ```toml
346
- [[pull.mappings]]
347
- src = "$XDG_CONFIG_HOME_MIRROR/nvim"
348
- dest = "$XDG_CONFIG_HOME/nvim"
458
+ [[sync.xdg_config]]
459
+ path = "nvim"
349
460
  ignore = ["lazy-lock.json", "plugin/packer_compiled.lua"]
350
461
  ```
351
462
 
352
463
  **Combining options:**
353
464
  ```toml
354
- [[push.mappings]]
355
- src = "$XDG_CONFIG_HOME/nvim"
356
- dest = "$DOTFILES_DIR/config/nvim"
465
+ [[sync.xdg_config]]
466
+ path = "nvim"
357
467
  only = ["lua", "init.lua"]
358
468
  ignore = ["lua/plugin/packer_compiled.lua"]
359
469
  force = true
@@ -426,7 +536,7 @@ By default, all `push` and `pull` commands run in preview mode:
426
536
 
427
537
  Dotsync provides clear, actionable error messages for common issues:
428
538
 
429
- - **Permission Errors**:
539
+ - **Permission Errors**:
430
540
  ```
431
541
  Permission denied: /path/to/file
432
542
  Try: chmod +w <path> or check file permissions
@@ -496,10 +606,8 @@ diff_created = "✨" # New files created
496
606
  diff_updated = "📝" # Files modified
497
607
  diff_removed = "🗑️ " # Files deleted
498
608
 
499
- # Example mappings section
500
- [[pull.mappings]]
501
- src = "$XDG_CONFIG_HOME_MIRROR"
502
- dest = "$XDG_CONFIG_HOME"
609
+ # Example sync mapping
610
+ [[sync.xdg_config]]
503
611
  ignore = ["cache"]
504
612
  ```
505
613
 
@@ -550,10 +658,10 @@ The check runs after your command completes and uses a cached timestamp to avoid
550
658
  ```bash
551
659
  # Work dotfiles
552
660
  dotsync -c ~/work-dotfiles.toml push --apply
553
-
661
+
554
662
  # Personal dotfiles
555
663
  dotsync -c ~/.config/personal.toml pull --apply
556
-
664
+
557
665
  # Server configs
558
666
  dotsync --config ~/server.toml push --apply
559
667
  ```
@@ -562,7 +670,7 @@ The check runs after your command completes and uses a cached timestamp to avoid
562
670
  ```shell
563
671
  # In a script or CI/CD pipeline
564
672
  dotsync pull --apply --yes --quiet
565
-
673
+
566
674
  # Shorthand
567
675
  dotsync push -ayq
568
676
  ```
@@ -604,14 +712,13 @@ The check runs after your command completes and uses a cached timestamp to avoid
604
712
 
605
713
  ## Common Use Cases
606
714
 
607
- Here are some practical examples of how to use Dotsync for popular configuration files:
715
+ Here are practical examples using bidirectional sync for popular configuration files:
608
716
 
609
717
  ### Syncing Neovim Configuration
610
718
 
611
719
  ```toml
612
- [[pull.mappings]]
613
- src = "$HOME/dotfiles/config/nvim"
614
- dest = "$HOME/.config/nvim"
720
+ [[sync.xdg_config]]
721
+ path = "nvim"
615
722
  force = true
616
723
  ignore = ["lazy-lock.json", ".luarc.json"]
617
724
  ```
@@ -619,31 +726,49 @@ ignore = ["lazy-lock.json", ".luarc.json"]
619
726
  ### Syncing Terminal Emulator (Alacritty)
620
727
 
621
728
  ```toml
622
- [[push.mappings]]
623
- src = "$HOME/.config/alacritty"
624
- dest = "$HOME/dotfiles/config/alacritty"
729
+ [[sync.xdg_config]]
730
+ path = "alacritty"
625
731
  only = ["alacritty.toml", "themes"]
626
732
  ```
627
733
 
628
734
  ### Syncing Shell Configuration
629
735
 
630
736
  ```toml
631
- [[pull.mappings]]
632
- src = "$HOME/dotfiles/shell/.zshrc"
633
- dest = "$HOME"
737
+ [[sync.home]]
738
+ path = ".zshenv"
634
739
 
635
- [[pull.mappings]]
636
- src = "$HOME/dotfiles/shell/.zshenv"
637
- dest = "$HOME"
740
+ [[sync.xdg_config]]
741
+ path = "zsh"
742
+ ignore = [".zsh_sessions", ".zsh_history", ".zcompdump"]
638
743
  ```
639
744
 
640
745
  ### Syncing Multiple Config Directories
641
746
 
642
747
  ```toml
643
- [[pull.mappings]]
644
- src = "$HOME/dotfiles/config"
645
- dest = "$HOME/.config"
646
- ignore = ["nvim", "cache", "*.log"]
748
+ [[sync.xdg_config]]
749
+ only = ["nvim", "alacritty", "git", "zsh", "tmux", "starship.toml"]
750
+ force = true
751
+ ```
752
+
753
+ ### Per-Machine Configuration Files
754
+
755
+ Use different config files for different machines:
756
+
757
+ ```toml
758
+ # In dotsync.macbook.toml
759
+ [[sync.mappings]]
760
+ local = "$XDG_CONFIG_HOME/dotsync.toml"
761
+ remote = "$XDG_CONFIG_HOME_MIRROR/dotsync/dotsync.macbook.toml"
762
+
763
+ # In dotsync.work.toml
764
+ [[sync.mappings]]
765
+ local = "$XDG_CONFIG_HOME/dotsync.toml"
766
+ remote = "$XDG_CONFIG_HOME_MIRROR/dotsync/dotsync.work.toml"
767
+ ```
768
+
769
+ Then use `-c` flag to select the appropriate config:
770
+ ```shell
771
+ dotsync -c ~/.config/dotsync/dotsync.macbook.toml push --apply
647
772
  ```
648
773
 
649
774
  ## Troubleshooting
@@ -652,7 +777,7 @@ ignore = ["nvim", "cache", "*.log"]
652
777
 
653
778
  **Problem**: Icons appear as boxes, question marks, or strange characters.
654
779
 
655
- **Solution**:
780
+ **Solution**:
656
781
  - Install a [Nerd Font](https://www.nerdfonts.com/) and configure your terminal to use it
657
782
  - Or customize icons in `~/.config/dotsync.toml` using UTF-8 emojis or regular characters:
658
783
  ```toml
data/Rakefile CHANGED
@@ -15,23 +15,137 @@ end
15
15
  task default: :spec
16
16
 
17
17
  namespace :release do
18
- desc "Tag git with the current Dotsync::VERSION"
19
- task :tag do
20
- require_relative "./lib/dotsync/version"
21
- version = Dotsync::VERSION
18
+ desc "Generate CHANGELOG entry for a new version"
19
+ # Usage: rake release:changelog[0.2.1]
20
+ task :changelog, [:version] do |_t, args|
21
+ version = args[:version]
22
+ unless version
23
+ require_relative "./lib/dotsync/version"
24
+ version = Dotsync::VERSION
25
+ end
26
+ version = version.sub(/^v/, "")
27
+ today = Date.today.strftime("%Y-%m-%d")
28
+
29
+ latest_tag = `git describe --tags --abbrev=0 2>/dev/null`.strip
30
+ commits = if latest_tag.empty?
31
+ `git log --oneline --no-decorate`.strip.split("\n")
32
+ else
33
+ `git log #{latest_tag}..HEAD --oneline --no-decorate`.strip.split("\n")
34
+ end
35
+
36
+ if commits.empty?
37
+ abort "No commits since #{latest_tag}. Nothing to release."
38
+ end
39
+
40
+ categories = { "Added" => [], "Changed" => [], "Fixed" => [], "Removed" => [], "Security" => [], "Dependencies" => [] }
41
+
42
+ commits.each do |commit|
43
+ message = commit.sub(/^[a-f0-9]+\s+/, "")
44
+ case message.downcase
45
+ when /^add|^feat|^implement|^create|^new|^support/i then categories["Added"] << message
46
+ when /^fix|^bugfix|^hotfix|^resolve|^correct/i then categories["Fixed"] << message
47
+ when /^remove|^delete|^drop/i then categories["Removed"] << message
48
+ when /^security|^vuln|^cve/i then categories["Security"] << message
49
+ when /^bump|^upgrade|^update.*dependency|^dep/i then categories["Dependencies"] << message
50
+ else categories["Changed"] << message
51
+ end
52
+ end
53
+
54
+ changelog_entry = "## [#{version}] - #{today}\n"
55
+ categories.each do |category, items|
56
+ next if items.empty?
57
+ changelog_entry += "\n### #{category}\n\n"
58
+ items.each { |item| changelog_entry += "- #{item}\n" }
59
+ end
60
+
61
+ changelog_path = "CHANGELOG.md"
62
+ abort "CHANGELOG.md not found." unless File.exist?(changelog_path)
63
+
64
+ changelog = File.read(changelog_path)
65
+ abort "Version #{version} already exists in CHANGELOG.md" if changelog.include?("[#{version}]")
66
+
67
+ match = changelog.match(/^## \[/m)
68
+ new_changelog = match ? changelog.sub(/^## \[/m, "#{changelog_entry}\n## [") : changelog.rstrip + "\n\n#{changelog_entry}"
69
+
70
+ repo_url = `git remote get-url origin`.strip.sub(/\.git$/, "").sub(/^git@github\.com:/, "https://github.com/")
71
+ previous_version = latest_tag.empty? ? "v0.0.0" : latest_tag
72
+ link_entry = "[#{version}]: #{repo_url}/compare/#{previous_version}...v#{version}"
73
+
74
+ new_changelog = if new_changelog.match?(/^\[[\d.]+\]:.*compare/m)
75
+ new_changelog.sub(/^(\[[\d.]+\]:.*compare)/m, "#{link_entry}\n\\1")
76
+ else
77
+ new_changelog.rstrip + "\n\n#{link_entry}\n"
78
+ end
79
+
80
+ File.write(changelog_path, new_changelog)
81
+ puts "Updated CHANGELOG.md with version #{version}"
82
+ puts "\n#{changelog_entry}"
83
+ end
84
+
85
+ desc "Create annotated git tag from CHANGELOG"
86
+ # Usage: rake release:tag[0.2.1] or just rake release:tag (uses Dotsync::VERSION)
87
+ task :tag, [:version] do |_t, args|
88
+ version = args[:version]
89
+ unless version
90
+ require_relative "./lib/dotsync/version"
91
+ version = Dotsync::VERSION
92
+ end
93
+ version = version.sub(/^v/, "")
22
94
  tag_name = "v#{version}"
23
95
 
24
- # Check if tag already exists
25
96
  if `git tag --list`.split.include?(tag_name)
26
97
  puts "Tag #{tag_name} already exists."
27
98
  exit(1)
28
99
  end
29
100
 
101
+ changelog_path = "CHANGELOG.md"
102
+ abort "CHANGELOG.md not found." unless File.exist?(changelog_path)
103
+
104
+ changelog = File.read(changelog_path)
105
+ version_regex = /^## \[#{Regexp.escape(version)}\] - (\d{4}-\d{2}-\d{2})\n(.*?)(?=^## \[|\z)/m
106
+ match = changelog.match(version_regex)
107
+
108
+ unless match
109
+ abort "Version #{version} not found in CHANGELOG.md\nRun 'rake release:changelog[#{version}]' first."
110
+ end
111
+
112
+ date = match[1]
113
+ content = match[2].strip
114
+ tag_message = "#{version} - #{date}\n\n#{content}"
115
+
30
116
  puts "Tagging commit as #{tag_name}..."
31
- sh "git tag -a #{tag_name} -m 'Release #{tag_name}'"
32
- puts "Pushing tag #{tag_name} to origin..."
33
- sh "git push origin #{tag_name}"
34
- puts "Done!"
117
+ sh "git", "tag", "-a", tag_name, "-m", tag_message
118
+ puts "Tag created. Push with: git push origin #{tag_name}"
119
+ end
120
+
121
+ desc "Full release: update changelog, commit, tag, and push"
122
+ # Usage: rake release:publish[0.2.1] or rake release:publish (uses Dotsync::VERSION)
123
+ task :publish, [:version] do |_t, args|
124
+ version = args[:version]
125
+ unless version
126
+ require_relative "./lib/dotsync/version"
127
+ version = Dotsync::VERSION
128
+ end
129
+ version = version.sub(/^v/, "")
130
+
131
+ status = `git status --porcelain`.strip
132
+ uncommitted = status.split("\n").reject { |line| line.end_with?("CHANGELOG.md") }
133
+ abort "Uncommitted changes:\n#{uncommitted.join("\n")}" unless uncommitted.empty?
134
+
135
+ Rake::Task["release:changelog"].invoke(version)
136
+ puts "\nReview CHANGELOG.md, then press Enter to continue..."
137
+ $stdin.gets
138
+
139
+ sh "git", "add", "CHANGELOG.md"
140
+ sh "git", "commit", "-m", "Update CHANGELOG for v#{version}\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
141
+
142
+ Rake::Task["release:tag"].reenable
143
+ Rake::Task["release:tag"].invoke(version)
144
+
145
+ branch = `git rev-parse --abbrev-ref HEAD`.strip
146
+ sh "git", "push", "origin", branch
147
+ sh "git", "push", "origin", "v#{version}"
148
+ puts "\n✅ Released v#{version}"
35
149
  end
36
150
  end
37
151
 
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dotsync
4
+ # SyncMappings provides bidirectional mapping support.
5
+ # It reads [sync] section mappings and converts them to push or pull format.
6
+ #
7
+ # The [sync] section supports multiple sub-types:
8
+ #
9
+ # 1. Explicit mappings with [[sync.mappings]]:
10
+ # [[sync.mappings]]
11
+ # local = "$XDG_CONFIG_HOME/nvim"
12
+ # remote = "$XDG_CONFIG_HOME_MIRROR/nvim"
13
+ # force = true
14
+ # ignore = ["lazy-lock.json"]
15
+ #
16
+ # 2. XDG shorthand mappings that auto-expand environment variables:
17
+ # [[sync.xdg_config]]
18
+ # path = "nvim"
19
+ # force = true
20
+ # # Expands to: local=$XDG_CONFIG_HOME/nvim, remote=$XDG_CONFIG_HOME_MIRROR/nvim
21
+ #
22
+ # Supported shorthands:
23
+ # - sync.home: $HOME <-> $HOME_MIRROR
24
+ # - sync.xdg_config: $XDG_CONFIG_HOME <-> $XDG_CONFIG_HOME_MIRROR
25
+ # - sync.xdg_data: $XDG_DATA_HOME <-> $XDG_DATA_HOME_MIRROR
26
+ # - sync.xdg_cache: $XDG_CACHE_HOME <-> $XDG_CACHE_HOME_MIRROR
27
+ # - sync.xdg_bin: $XDG_BIN_HOME <-> $XDG_BIN_HOME_MIRROR
28
+ # - sync.mappings: explicit local/remote mappings
29
+ #
30
+ # For push: local → remote (src=local, dest=remote)
31
+ # For pull: remote → local (src=remote, dest=local)
32
+ module SyncMappings
33
+ SYNC_SECTION = "sync"
34
+ MAPPINGS_KEY = "mappings"
35
+
36
+ # Shorthand type definitions mapping to local/remote base paths
37
+ SHORTHANDS = {
38
+ "home" => { local: "$HOME", remote: "$HOME_MIRROR" },
39
+ "xdg_config" => { local: "$XDG_CONFIG_HOME", remote: "$XDG_CONFIG_HOME_MIRROR" },
40
+ "xdg_data" => { local: "$XDG_DATA_HOME", remote: "$XDG_DATA_HOME_MIRROR" },
41
+ "xdg_cache" => { local: "$XDG_CACHE_HOME", remote: "$XDG_CACHE_HOME_MIRROR" },
42
+ "xdg_bin" => { local: "$XDG_BIN_HOME", remote: "$XDG_BIN_HOME_MIRROR" }
43
+ }.freeze
44
+
45
+ def sync_mappings_for_push
46
+ all_sync_mappings(:push)
47
+ end
48
+
49
+ def sync_mappings_for_pull
50
+ all_sync_mappings(:pull)
51
+ end
52
+
53
+ def has_sync_mappings?
54
+ return false unless sync_section.is_a?(Hash)
55
+
56
+ explicit_mappings_raw.any? || shorthand_mappings_raw.any?
57
+ end
58
+
59
+ private
60
+ def all_sync_mappings(direction)
61
+ convert_explicit_mappings(direction: direction) + convert_shorthand_mappings(direction: direction)
62
+ end
63
+
64
+ def sync_section
65
+ @config[SYNC_SECTION]
66
+ end
67
+
68
+ # Explicit [[sync.mappings]] with local/remote keys
69
+ def explicit_mappings_raw
70
+ return [] unless sync_section.is_a?(Hash)
71
+ return [] unless sync_section.key?(MAPPINGS_KEY)
72
+
73
+ Array(sync_section[MAPPINGS_KEY])
74
+ end
75
+
76
+ def convert_explicit_mappings(direction:)
77
+ explicit_mappings_raw.map do |mapping|
78
+ converted = convert_explicit_mapping(mapping, direction)
79
+ Dotsync::Mapping.new(converted)
80
+ end
81
+ end
82
+
83
+ def convert_explicit_mapping(mapping, direction)
84
+ local = mapping["local"]
85
+ remote = mapping["remote"]
86
+
87
+ base = case direction
88
+ when :push
89
+ { "src" => local, "dest" => remote }
90
+ when :pull
91
+ { "src" => remote, "dest" => local }
92
+ end
93
+
94
+ # Preserve other options
95
+ base["force"] = mapping["force"] if mapping.key?("force")
96
+ base["ignore"] = mapping["ignore"] if mapping.key?("ignore")
97
+ base["only"] = mapping["only"] if mapping.key?("only")
98
+
99
+ base
100
+ end
101
+
102
+ # Shorthand mappings: [[sync.home]], [[sync.xdg_config]], etc.
103
+ def shorthand_mappings_raw
104
+ return [] unless sync_section.is_a?(Hash)
105
+
106
+ mappings = []
107
+ SHORTHANDS.each_key do |shorthand_type|
108
+ next unless sync_section.key?(shorthand_type)
109
+ Array(sync_section[shorthand_type]).each do |mapping|
110
+ mappings << { type: shorthand_type, mapping: mapping }
111
+ end
112
+ end
113
+ mappings
114
+ end
115
+
116
+ def convert_shorthand_mappings(direction:)
117
+ shorthand_mappings_raw.map do |entry|
118
+ converted = convert_shorthand_mapping(entry[:type], entry[:mapping], direction)
119
+ Dotsync::Mapping.new(converted)
120
+ end
121
+ end
122
+
123
+ def convert_shorthand_mapping(shorthand_type, mapping, direction)
124
+ shorthand_def = SHORTHANDS[shorthand_type]
125
+
126
+ # Support both 'path' for single paths and 'only' for multiple paths
127
+ path = mapping["path"]
128
+ only = mapping["only"]
129
+
130
+ local = build_path(shorthand_def[:local], path)
131
+ remote = build_path(shorthand_def[:remote], path)
132
+
133
+ base = case direction
134
+ when :push
135
+ { "src" => local, "dest" => remote }
136
+ when :pull
137
+ { "src" => remote, "dest" => local }
138
+ end
139
+
140
+ # Preserve other options
141
+ base["force"] = mapping["force"] if mapping.key?("force")
142
+ base["ignore"] = mapping["ignore"] if mapping.key?("ignore")
143
+ base["only"] = only if only
144
+
145
+ base
146
+ end
147
+
148
+ def build_path(base, path)
149
+ path ? File.join(base, path) : base
150
+ end
151
+
152
+ def validate_sync_mappings!
153
+ return unless sync_section
154
+
155
+ unless sync_section.is_a?(Hash)
156
+ raise Dotsync::ConfigError,
157
+ "Configuration error: [sync] must be a table, not an array. " \
158
+ "Use [[sync.mappings]] for explicit mappings."
159
+ end
160
+
161
+ validate_explicit_mappings!
162
+ validate_shorthand_mappings!
163
+ end
164
+
165
+ def validate_explicit_mappings!
166
+ return unless sync_section.key?(MAPPINGS_KEY)
167
+
168
+ explicit_mappings_raw.each_with_index do |mapping, index|
169
+ unless mapping.is_a?(Hash) && mapping.key?("local") && mapping.key?("remote")
170
+ raise Dotsync::ConfigError,
171
+ "Configuration error in sync.mappings ##{index + 1}: " \
172
+ "Each mapping must have 'local' and 'remote' keys."
173
+ end
174
+ end
175
+ end
176
+
177
+ def validate_shorthand_mappings!
178
+ SHORTHANDS.each_key do |shorthand_type|
179
+ next unless sync_section.key?(shorthand_type)
180
+
181
+ Array(sync_section[shorthand_type]).each_with_index do |mapping, index|
182
+ unless mapping.is_a?(Hash)
183
+ raise Dotsync::ConfigError,
184
+ "Configuration error in sync.#{shorthand_type} ##{index + 1}: " \
185
+ "Each mapping must be a table."
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -3,10 +3,10 @@
3
3
  module Dotsync
4
4
  class PullActionConfig < BaseConfig
5
5
  include XDGBaseDirectory
6
+ include SyncMappings
6
7
 
7
8
  def mappings
8
- mappings_list = section["mappings"]
9
- Array(mappings_list).map { |mapping| Dotsync::Mapping.new(mapping) }
9
+ section_mappings + sync_mappings_for_pull
10
10
  end
11
11
 
12
12
  def backups_root
@@ -20,13 +20,31 @@ module Dotsync
20
20
  SECTION_NAME
21
21
  end
22
22
 
23
+ def section_mappings
24
+ return [] unless section && section["mappings"]
25
+ Array(section["mappings"]).map { |mapping| Dotsync::Mapping.new(mapping) }
26
+ end
27
+
23
28
  def validate!
24
- validate_section_present!
25
- validate_key_present! "mappings"
29
+ validate_pull_or_sync_present!
30
+ validate_pull_mappings!
31
+ validate_sync_mappings!
32
+ end
33
+
34
+ def validate_pull_or_sync_present!
35
+ has_pull = @config.key?(section_name) && section["mappings"]&.any?
36
+
37
+ unless has_pull || has_sync_mappings?
38
+ raise_error "No [#{section_name}] mappings or [sync] mappings found in config file"
39
+ end
40
+ end
41
+
42
+ def validate_pull_mappings!
43
+ return unless section && section["mappings"]
26
44
 
27
45
  Array(section["mappings"]).each_with_index do |mapping, index|
28
46
  unless mapping.is_a?(Hash) && mapping.key?("src") && mapping.key?("dest")
29
- raise "Configuration error in mapping ##{index + 1}: Each mapping must have 'src' and 'dest' keys."
47
+ raise "Configuration error in pull mapping ##{index + 1}: Each mapping must have 'src' and 'dest' keys."
30
48
  end
31
49
  end
32
50
  end
@@ -2,9 +2,10 @@
2
2
 
3
3
  module Dotsync
4
4
  class PushActionConfig < BaseConfig
5
+ include SyncMappings
6
+
5
7
  def mappings
6
- mappings_list = section["mappings"]
7
- Array(mappings_list).map { |mapping| Dotsync::Mapping.new(mapping) }
8
+ section_mappings + sync_mappings_for_push
8
9
  end
9
10
 
10
11
  private
@@ -14,13 +15,31 @@ module Dotsync
14
15
  SECTION_NAME
15
16
  end
16
17
 
18
+ def section_mappings
19
+ return [] unless section && section["mappings"]
20
+ Array(section["mappings"]).map { |mapping| Dotsync::Mapping.new(mapping) }
21
+ end
22
+
17
23
  def validate!
18
- validate_section_present!
19
- validate_key_present! "mappings"
24
+ validate_push_or_sync_present!
25
+ validate_push_mappings!
26
+ validate_sync_mappings!
27
+ end
28
+
29
+ def validate_push_or_sync_present!
30
+ has_push = @config.key?(section_name) && section["mappings"]&.any?
31
+
32
+ unless has_push || has_sync_mappings?
33
+ raise_error "No [#{section_name}] mappings or [sync] mappings found in config file"
34
+ end
35
+ end
36
+
37
+ def validate_push_mappings!
38
+ return unless section && section["mappings"]
20
39
 
21
40
  Array(section["mappings"]).each_with_index do |mapping, index|
22
41
  unless mapping.is_a?(Hash) && mapping.key?("src") && mapping.key?("dest")
23
- raise "Configuration error in mapping ##{index + 1}: Each mapping must have 'src' and 'dest' keys."
42
+ raise "Configuration error in push mapping ##{index + 1}: Each mapping must have 'src' and 'dest' keys."
24
43
  end
25
44
  end
26
45
  end
@@ -16,6 +16,10 @@ require_relative "../utils/config_cache"
16
16
  require_relative "../models/mapping"
17
17
  require_relative "../models/diff"
18
18
 
19
+ # Config Concerns
20
+ require_relative "../config/concerns/xdg_base_directory"
21
+ require_relative "../config/concerns/sync_mappings"
22
+
19
23
  # Config
20
24
  require_relative "../config/base_config"
21
25
  require_relative "../config/pull_action_config"
@@ -16,6 +16,9 @@ require_relative "../utils/config_cache"
16
16
  require_relative "../models/mapping"
17
17
  require_relative "../models/diff"
18
18
 
19
+ # Config Concerns
20
+ require_relative "../config/concerns/sync_mappings"
21
+
19
22
  # Config
20
23
  require_relative "../config/base_config"
21
24
  require_relative "../config/push_action_config"
@@ -5,6 +5,7 @@ module Dotsync
5
5
  def initialize(logger: nil, config_path: nil)
6
6
  @logger = logger || Dotsync::Logger.new
7
7
  @config_path = config_path
8
+ Dotsync.config_path = config_path if config_path
8
9
  end
9
10
 
10
11
  # action_name should be a symbol, e.g., :pull, :watch, :sync
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dotsync
4
- VERSION = "0.1.25"
4
+ VERSION = "0.1.26"
5
5
  end
data/lib/dotsync.rb CHANGED
@@ -22,6 +22,7 @@ require_relative "dotsync/version"
22
22
 
23
23
  # Config Concerns (loaded early as they're used by other modules)
24
24
  require_relative "dotsync/config/concerns/xdg_base_directory"
25
+ require_relative "dotsync/config/concerns/sync_mappings"
25
26
 
26
27
  # Utils
27
28
  require_relative "dotsync/utils/path_utils"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dotsync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.25
4
+ version: 0.1.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Sáenz
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-11-16 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: toml-rb
@@ -285,9 +284,10 @@ extensions: []
285
284
  extra_rdoc_files: []
286
285
  files:
287
286
  - ".editorconfig"
288
- - ".github/workflows/gem-push.yml"
289
- - ".github/workflows/gem-push.yml.bak"
287
+ - ".github/workflows/ci.yml"
288
+ - ".github/workflows/release.yml"
290
289
  - ".gitignore"
290
+ - ".pre-commit-config.yaml"
291
291
  - ".rspec"
292
292
  - ".rubocop.yml"
293
293
  - ".ruby-version"
@@ -317,6 +317,7 @@ files:
317
317
  - lib/dotsync/actions/watch_action.rb
318
318
  - lib/dotsync/colors.rb
319
319
  - lib/dotsync/config/base_config.rb
320
+ - lib/dotsync/config/concerns/sync_mappings.rb
320
321
  - lib/dotsync/config/concerns/xdg_base_directory.rb
321
322
  - lib/dotsync/config/pull_action_config.rb
322
323
  - lib/dotsync/config/push_action_config.rb
@@ -346,7 +347,6 @@ metadata:
346
347
  homepage_uri: https://github.com/dsaenztagarro/dotsync
347
348
  source_code_uri: https://github.com/dsaenztagarro/dotsync
348
349
  changelog_uri: https://github.com/dsaenztagarro/dotsync/blob/master/CHANGELOG.md
349
- post_install_message:
350
350
  rdoc_options: []
351
351
  require_paths:
352
352
  - lib
@@ -361,8 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
361
  - !ruby/object:Gem::Version
362
362
  version: '0'
363
363
  requirements: []
364
- rubygems_version: 3.4.19
365
- signing_key:
364
+ rubygems_version: 3.7.2
366
365
  specification_version: 4
367
366
  summary: Manage dotfiles like a boss
368
367
  test_files: []
@@ -1,45 +0,0 @@
1
- jobs:
2
- build:
3
- name: Build + Publish
4
- runs-on: ubuntu-latest
5
- permissions:
6
- contents: read
7
- packages: write
8
-
9
- steps:
10
- - uses: actions/checkout@v4
11
-
12
- - name: Publish to GPR
13
- run: |
14
- mkdir -p $HOME/.gem
15
- touch $HOME/.gem/credentials
16
- chmod 0600 $HOME/.gem/credentials
17
- printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
18
- gem build *.gemspec
19
- gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
20
- env:
21
- GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
22
- OWNER: ${{ github.repository_owner }}
23
-
24
- publish:
25
- needs: test
26
- runs-on: ubuntu-latest
27
- if: github.ref == 'refs/heads/master' && matrix.ruby == '3.2'
28
-
29
- steps:
30
- - uses: actions/checkout@v4
31
-
32
- - name: Set up Ruby
33
- uses: ruby/setup-ruby@v1
34
- with:
35
- ruby-version: 3.2
36
- bundler-cache: true
37
-
38
- - name: Check if gem version has changed
39
- id: gem_version_check
40
- run: |
41
- gem build *.gemspec
42
- gem_name=$(ls *.gem | head -n 1)
43
- gem info $gem_name --remote || echo "new_version" > version_changed
44
- env:
45
- GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"