label_weaver 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: