label_weaver 0.0.3 → 0.0.5

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: 8d4577814ad253da907628f3c86300dc89c2b362260fa6772af602670ce2aa63
4
- data.tar.gz: a262362d186dca07c7789baca7cd642c3d9b43e5ea1ca3ec6259ac4a244ef90f
3
+ metadata.gz: 6bbe89444ed69fe936e7e64cb7c0e2b36c013df2afef71f1b33ae65a17e67fa3
4
+ data.tar.gz: db4917c239cf6502e3da219f7fe215af11d5fa5dd3668e16b01fad2389c93243
5
5
  SHA512:
6
- metadata.gz: 64c146c67e07cb609d4c7ac458e37d071edd0e592ec460f3b692b559a5121b2dfa12c5294a71eb565cb7d2064d54053aae8a0cf09ccdae2fc94fe48f4970cbcd
7
- data.tar.gz: 17f74363825bd9115228468d77b175b19c2895a680acd3809e0a7d25f3dda1338cae90e660fd26140fc57b78cd6aff80dd99f405938141d46cfcb5d56104d131
6
+ metadata.gz: edb992f4593c2de938debe63bc4ee1f60bf4f308b80e859a82c1fb6e3318f45aca96096c8b0859f33c72e916f61f2bffb5f627af4effae44b4135313490b92f1
7
+ data.tar.gz: 2d51c191608b5070f20f31ef818b26d4d21d67839427655974e8ff55b3911ce41b3a501418e9151bd1d61f8fc1d49393fdaa68f01e225d673687913f8a59f553
data/README.md CHANGED
@@ -1,3 +1,66 @@
1
1
  # LabelWeaver
2
2
 
3
3
  [![Ruby Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/standardrb/standard)
4
+ [![Gem Version](https://badge.fury.io/rb/label_weaver.svg)](https://badge.fury.io/rb/label_weaver)
5
+
6
+ <!-- TOC -->
7
+ * [LabelWeaver](#labelweaver)
8
+ * [Installation](#installation)
9
+ * [Setting up a new whitelabel project](#setting-up-a-new-whitelabel-project)
10
+ * [Developing a whitelabel project](#developing-a-whitelabel-project)
11
+ * [Starting local development](#starting-local-development)
12
+ * [Stopping local development](#stopping-local-development)
13
+ * [Diffs](#diffs)
14
+ * [CI Usage](#ci-usage)
15
+ <!-- TOC -->
16
+
17
+ LabelWeaver is a gem to help developing whitelabel applications of an existing code base.
18
+
19
+ It does so by automatically merging the base code into the whitelabel code, leading to only the
20
+ changed files being part of a new repository or branch.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ gem install label_weaver
26
+ ```
27
+
28
+ ## Setting up a new whitelabel project
29
+
30
+ ## Developing a whitelabel project
31
+
32
+ ### Starting local development
33
+
34
+ ```
35
+ label_weaver develop --start
36
+ ```
37
+
38
+ This command will perform the following actions:
39
+
40
+ 1. Run any `before_start` hooks
41
+ 2. Clone or check out the base repository
42
+ 3. Copy all files from the base repository to the whitelabel project that do not already exist
43
+ 4. Merge configured files
44
+ 5. Run any `after_start` hooks
45
+
46
+ Please note that the gem will inform you about files with a newer version in the base repository.
47
+ This could mean that you have to update them in your whitelabel project as well to ensure compatibility.
48
+
49
+ ### Stopping local development
50
+
51
+ ```
52
+ label_weaver develop --stop
53
+ ```
54
+
55
+ This command will perform the following actions:
56
+
57
+ 1. Run any `before_start` hooks
58
+ 2. Restore all files that were automatically created through merging
59
+ 3. Remove all files from the project that do not differ from the base project
60
+ 4. Run any `after_start` hooks
61
+
62
+ You should be left with only the changed files in your repository now.
63
+
64
+ ### Diffs
65
+
66
+ ## CI Usage
data/label_weaver.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "label_weaver"
5
- spec.version = "0.0.3"
5
+ spec.version = "0.0.5"
6
6
  spec.authors = ["Stefan Exner"]
7
7
  spec.email = ["stex@stex.codes"]
8
8
  spec.homepage = "https://gitlab.com/lopo-tech/label_weaver"
@@ -17,10 +17,8 @@ Gem::Specification.new do |spec|
17
17
  spec.required_ruby_version = "~> 3.3"
18
18
  spec.add_dependency "cogger", "~> 0.21"
19
19
  spec.add_dependency "containable", "~> 0.0"
20
- spec.add_dependency "dry-monads", "~> 1.6"
21
20
  spec.add_dependency "dry-schema", "~> 1.6"
22
21
  spec.add_dependency "diffy", "~> 3.4"
23
- spec.add_dependency "etcher", "~> 1.6"
24
22
  spec.add_dependency "git", "~> 2.1.1"
25
23
  spec.add_dependency "infusible", "~> 3.5"
26
24
  spec.add_dependency "ruby-next-core", "~> 1.0"
@@ -22,8 +22,11 @@ module LabelWeaver
22
22
  kernel.exit(1)
23
23
  end
24
24
 
25
+ Hooks.new.run(:develop, :before_start)
25
26
  repo.clone_or_update
26
27
  copy_repository_files
28
+ handle_file_merges
29
+ Hooks.new.run(:develop, :after_start)
27
30
  end
28
31
 
29
32
  private
@@ -49,11 +52,20 @@ module LabelWeaver
49
52
  end
50
53
  end
51
54
 
55
+ def handle_file_merges
56
+ merger = ::LabelWeaver::Merger.new(project_root_dir: context.project_root_dir, repo:)
57
+ if merger.present?
58
+ logger.info "Merging files..."
59
+
60
+ merger.merge!
61
+ end
62
+ end
63
+
52
64
  def repo
53
65
  @repo ||= LabelWeaver::TempRepo.new(
54
66
  context.repository_dir,
55
- repository_url: configuration.git_repository,
56
- branch: configuration.git_branch,
67
+ repository_url: configuration.git[:repository],
68
+ branch: configuration.git[:branch],
57
69
  excludes: configuration.excludes,
58
70
  logger: logger
59
71
  )
@@ -22,7 +22,10 @@ module LabelWeaver
22
22
  kernel.exit(1)
23
23
  end
24
24
 
25
+ Hooks.new.run(:develop, :before_stop)
26
+ restore_merged_files
25
27
  remove_base_files
28
+ Hooks.new.run(:develop, :after_stop)
26
29
  end
27
30
 
28
31
  private
@@ -35,9 +38,8 @@ module LabelWeaver
35
38
  project_file = context.project_root_dir + relative_filename
36
39
 
37
40
  if project_file.exist?
38
- # TODO: Should we get a time component in here to check for possible newer base repo files?
39
41
  if digest(project_file) != digest(repository_file)
40
- logger.info "File '#{relative_filename}' is kept as it was changed in the whitelabel project (r: #{repo.timestamp_for(repository_file)} vs w: #{project_file.mtime})."
42
+ logger.debug "File '#{relative_filename}' is kept as it was changed in the whitelabel project (r: #{repo.timestamp_for(repository_file)} vs w: #{project_file.mtime})."
41
43
  else
42
44
  logger.debug "Deleting file '#{relative_filename}'..."
43
45
  project_file.unlink
@@ -57,6 +59,15 @@ module LabelWeaver
57
59
  remove_empty_tree(dir.parent)
58
60
  end
59
61
 
62
+ def restore_merged_files
63
+ merger = ::LabelWeaver::Merger.new(project_root_dir: context.project_root_dir, repo:)
64
+ if merger.present?
65
+ logger.info "Restoring merged files..."
66
+
67
+ merger.restore!
68
+ end
69
+ end
70
+
60
71
  def digest(file)
61
72
  Digest::SHA1.file(file).hexdigest
62
73
  end
@@ -64,8 +75,8 @@ module LabelWeaver
64
75
  def repo
65
76
  @repo ||= LabelWeaver::TempRepo.new(
66
77
  context.repository_dir,
67
- repository_url: configuration.git_repository,
68
- branch: configuration.git_branch,
78
+ repository_url: configuration.git[:repository],
79
+ branch: configuration.git[:branch],
69
80
  excludes: configuration.excludes,
70
81
  logger: logger
71
82
  )
@@ -39,7 +39,6 @@ module LabelWeaver
39
39
  project_root_dir: Pathname.new(Dir.pwd),
40
40
  local_tmp_dir: Pathname.new(Dir.pwd).join(".config", "label_weaver"),
41
41
  repository_dir: Pathname.new(Dir.pwd).join(".config", "label_weaver", "repository"),
42
- tracking_file: Pathname.new(Dir.pwd).join(".config", "label_weaver", "files.yml"),
43
42
  defaults_path:,
44
43
  xdg_config:,
45
44
  version_label: specification.labeled_version
@@ -2,14 +2,23 @@
2
2
 
3
3
  require "dry/schema"
4
4
 
5
- Dry::Schema.load_extensions :monads
6
-
7
5
  module LabelWeaver
8
6
  module Configuration
9
7
  Contract = Dry::Schema.Params do
10
- required(:git_repository).filled :string
11
- required(:git_branch).filled :string
8
+ required(:git).hash do
9
+ required(:repository).filled(:string)
10
+ required(:branch).filled(:string)
11
+ end
12
12
  optional(:excludes).array :string
13
+ optional(:hooks).hash do
14
+ optional(:develop).hash do
15
+ optional(:before_start).array(:string)
16
+ optional(:after_start).array(:string)
17
+ optional(:before_stop).array(:string)
18
+ optional(:after_stop).array(:string)
19
+ end
20
+ end
21
+ optional(:merges).array(:hash)
13
22
  end
14
23
  end
15
24
  end
@@ -5,6 +5,19 @@ git:
5
5
  # Shell filename globbing rules apply, not regular expressions
6
6
  excludes:
7
7
  - .git/**
8
+ hooks:
9
+ develop:
10
+ after_start:
11
+ - echo "Development Mode Started"
12
+
13
+ # Define files from the base and whitelabel projects that should be merged into
14
+ # a new or existing file.
15
+ # Currently supported formats are JSON and YAML
16
+ #merges:
17
+ # - source_file: package.json
18
+ # target_file: package.json
19
+ # overrides_file: package.whitelabel.json
20
+
8
21
  # Files here will be appended on whitelabel development instead of being skipped if the
9
22
  # file already exists in a project
10
23
  #append:
@@ -5,8 +5,13 @@ module LabelWeaver
5
5
  # Defines the configuration model for use throughout the gem.
6
6
  Model = Data.define(
7
7
  :excludes,
8
- :git_repository,
9
- :git_branch
10
- )
8
+ :git,
9
+ :hooks,
10
+ :merges
11
+ ) do
12
+ def initialize(git:, hooks: {}, excludes: [], merges: [])
13
+ super
14
+ end
15
+ end
11
16
  end
12
17
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "cogger"
4
4
  require "containable"
5
- require "etcher"
6
5
  require "runcom"
7
6
  require "spek"
8
7
 
@@ -12,19 +11,29 @@ module LabelWeaver
12
11
  extend Containable
13
12
 
14
13
  register :configuration do
15
- self[:defaults].add_loader(:yaml, self[:xdg_config].active)
16
- .then { |registry| Etcher.call registry }
14
+ if self[:xdg_config].active
15
+ data = self[:defaults].merge(YAML.load_file(self[:xdg_config].active, symbolize_names: true))
16
+ contract = Configuration::Contract.call(**data)
17
+
18
+ raise ArgumentError.new(contract.errors.to_h) if contract.failure?
19
+
20
+ Configuration::Model.new(**data)
21
+ else
22
+ Configuration::Model.new(**self[:defaults])
23
+ end
17
24
  end
18
25
 
19
26
  register :defaults do
20
- Etcher::Registry.new(contract: Configuration::Contract, model: Configuration::Model)
21
- .add_loader(:yaml, self[:defaults_path])
27
+ YAML.load_file(self[:defaults_path], symbolize_names: true)
22
28
  end
23
29
 
24
30
  register(:specification) { Spek::Loader.call "#{__dir__}/../../label_weaver.gemspec" }
25
31
  register(:defaults_path) { Pathname(__dir__).join("configuration/defaults.yml") }
26
32
  register(:xdg_config) { Runcom::Config.new("label_weaver/configuration.yml") }
27
- register(:logger) { Cogger.new(id: "label_weaver") }
33
+ register(:logger) do
34
+ Cogger.add_emoji :any, "🪝"
35
+ Cogger.new(id: "label_weaver")
36
+ end
28
37
  register :kernel, Kernel
29
38
  end
30
39
  end
@@ -0,0 +1,12 @@
1
+ module LabelWeaver
2
+ class Hooks
3
+ include Import[:configuration, :logger]
4
+
5
+ def run(*path)
6
+ configuration.hooks.dig(*path)&.each do |hook|
7
+ logger.any "$> #{hook}"
8
+ system(hook)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,77 @@
1
+ module LabelWeaver
2
+ class Merger
3
+ include Import[:configuration, :logger]
4
+
5
+ attr_reader :project_root_dir, :repo
6
+
7
+ def initialize(project_root_dir:, repo:, configuration: nil, logger: nil)
8
+ @configuration = configuration
9
+ @logger = logger
10
+ @project_root_dir = project_root_dir
11
+ @repo = repo
12
+ end
13
+
14
+ def present?
15
+ merge_entries.any?
16
+ end
17
+
18
+ def merge!
19
+ merge_entries.each do |entry|
20
+ entry => {source_file:, target_file:, overrides_file:}
21
+ logger.debug "Merging '#{overrides_file}' and '#{source_file}' into '#{target_file}'..."
22
+
23
+ merge_file(project_root_dir + source_file, project_root_dir + target_file, project_root_dir + overrides_file)
24
+ end
25
+ end
26
+
27
+ def restore!
28
+ merge_entries.each do |entry|
29
+ logger.debug "Restoring '#{entry[:target_file]}'..."
30
+
31
+ restore_file(entry[:target_file])
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def merge_file(source_file, target_file, overrides_file)
38
+ source = load_file(source_file)
39
+ overrides = load_file(overrides_file)
40
+
41
+ write_file(target_file, source.deep_merge(overrides))
42
+ end
43
+
44
+ def restore_file(relative_file_path)
45
+ repository_file = repo.root_path + relative_file_path
46
+ project_file = project_root_dir + relative_file_path
47
+
48
+ FileUtils.cp(repository_file, project_file, preserve: true)
49
+ end
50
+
51
+ def merge_entries
52
+ configuration.merges.map { _1.transform_keys(&:to_sym) }
53
+ end
54
+
55
+ def load_file(file)
56
+ case file.extname
57
+ when ".yaml", ".yml"
58
+ YAML.load_file(file)
59
+ when ".json"
60
+ JSON.parse(File.read(file))
61
+ else
62
+ raise ArgumentError, "Unsupported file type: #{file.extname}"
63
+ end
64
+ end
65
+
66
+ def write_file(file, content)
67
+ case file.extname
68
+ when ".yaml", ".yml"
69
+ File.write(file, content.to_yaml)
70
+ when ".json"
71
+ File.write(file, JSON.pretty_generate(content))
72
+ else
73
+ raise ArgumentError, "Unsupported file type: #{file.extname}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -17,6 +17,8 @@ module LabelWeaver
17
17
  @logger = logger
18
18
  end
19
19
 
20
+ alias_method :root_path, :repository_path
21
+
20
22
  #
21
23
  # @return [Time] the last time the file was part of a commit, closest we can get to an mtime
22
24
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: label_weaver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Exner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-27 00:00:00.000000000 Z
11
+ date: 2024-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cogger
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.0'
41
- - !ruby/object:Gem::Dependency
42
- name: dry-monads
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.6'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.6'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: dry-schema
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +66,6 @@ dependencies:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
68
  version: '3.4'
83
- - !ruby/object:Gem::Dependency
84
- name: etcher
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.6'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '1.6'
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: git
99
71
  requirement: !ruby/object:Gem::Requirement
@@ -246,7 +218,9 @@ files:
246
218
  - lib/label_weaver/configuration/defaults.yml
247
219
  - lib/label_weaver/configuration/model.rb
248
220
  - lib/label_weaver/container.rb
221
+ - lib/label_weaver/hooks.rb
249
222
  - lib/label_weaver/import.rb
223
+ - lib/label_weaver/merger.rb
250
224
  - lib/label_weaver/temp_repo.rb
251
225
  homepage: https://gitlab.com/lopo-tech/label_weaver
252
226
  licenses: