physique 0.2.2
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 +15 -0
- data/.gitignore +36 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +60 -0
- data/README.md +41 -0
- data/Rakefile +6 -0
- data/lib/physique.rb +22 -0
- data/lib/physique/config.rb +24 -0
- data/lib/physique/dsl.rb +76 -0
- data/lib/physique/project.rb +34 -0
- data/lib/physique/solution.rb +69 -0
- data/lib/physique/task_builders/build.rb +62 -0
- data/lib/physique/task_builders/default.rb +9 -0
- data/lib/physique/task_builders/fluent_migrator.rb +227 -0
- data/lib/physique/task_builders/nuget.rb +45 -0
- data/lib/physique/task_builders/octopus.rb +147 -0
- data/lib/physique/task_builders/publish_nugets.rb +133 -0
- data/lib/physique/task_builders/test.rb +44 -0
- data/lib/physique/tasks/fluent_migrator.rb +159 -0
- data/lib/physique/tasks/nugets_pack.rb +12 -0
- data/lib/physique/tasks/octopus_pack.rb +141 -0
- data/lib/physique/tasks/sqlcmd.rb +110 -0
- data/lib/physique/tasks/versionizer.rb +113 -0
- data/lib/physique/tasks_builder.rb +58 -0
- data/lib/physique/tool_locator.rb +42 -0
- data/lib/physique/version.rb +3 -0
- data/physique.gemspec +26 -0
- data/spec/config_spec.rb +22 -0
- data/spec/project_spec.rb +26 -0
- data/spec/solution_spec.rb +12 -0
- data/spec/sqlcmd_spec.rb +146 -0
- data/spec/tool_locator_spec.rb +22 -0
- metadata +151 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'xsemver'
|
2
|
+
require 'albacore/logging'
|
3
|
+
|
4
|
+
module Physique
|
5
|
+
module Tasks
|
6
|
+
# Versionizer does versioning ITS OWN WAY!
|
7
|
+
#
|
8
|
+
# Defines ENV vars:
|
9
|
+
# * BUILD_VERSION
|
10
|
+
# * NUGET_VERSION
|
11
|
+
# * FORMAL_VERSION
|
12
|
+
#
|
13
|
+
# Publishes symbol :build_version
|
14
|
+
module Versionizer
|
15
|
+
# adds a new task with the given symbol to the Rake/Albacore application
|
16
|
+
# You can use this like any other albacore method, such as build,
|
17
|
+
# in order to give it parameters or dependencies, but there is no
|
18
|
+
# configuration object that you can configure. Copy-n-paste this
|
19
|
+
# code if you want something of your own.
|
20
|
+
#
|
21
|
+
def self.new(*sym)
|
22
|
+
version = gitflow_version(XSemVer::SemVer.find)
|
23
|
+
version_data = define_versions(version)
|
24
|
+
|
25
|
+
Albacore.subscribe :build_version do |data|
|
26
|
+
ENV['BUILD_VERSION'] = data.build_version
|
27
|
+
ENV['NUGET_VERSION'] = data.nuget_version
|
28
|
+
ENV['FORMAL_VERSION'] = data.formal_version
|
29
|
+
ENV['LONG_VERSION'] = data.long_version
|
30
|
+
end
|
31
|
+
|
32
|
+
Albacore.define_task(*sym) do
|
33
|
+
Albacore.publish :build_version, OpenStruct.new(version_data)
|
34
|
+
end
|
35
|
+
|
36
|
+
Albacore.define_task :version do
|
37
|
+
puts version_data.inspect
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.define_versions(semver)
|
42
|
+
build = build_number
|
43
|
+
|
44
|
+
{
|
45
|
+
# just a monotonic inc
|
46
|
+
:semver => semver,
|
47
|
+
:build_number => build,
|
48
|
+
:current_branch => current_branch,
|
49
|
+
|
50
|
+
# purely M.m.p format
|
51
|
+
:formal_version => "#{semver.format('%M.%m.%p')}",
|
52
|
+
|
53
|
+
# four-numbers version, useful if you're dealing with COM/Windows
|
54
|
+
:long_version => "#{semver.format('%M.%m.%p')}.#{build}",
|
55
|
+
|
56
|
+
# extensible number w/ git hash
|
57
|
+
:build_version => "#{semver.format('%M.%m.%p%s')}.#{last_commit[0]}",
|
58
|
+
|
59
|
+
# nuget (not full semver 2.0.0-rc.1 support) see http://nuget.codeplex.com/workitem/1796
|
60
|
+
:nuget_version => semver.format('%M.%m.%p%s')
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# load the commit data
|
65
|
+
# returns: [short-commit :: String]
|
66
|
+
#
|
67
|
+
def self.last_commit
|
68
|
+
begin
|
69
|
+
`git rev-parse --short HEAD`.chomp[0,6]
|
70
|
+
rescue
|
71
|
+
(ENV['BUILD_VCS_NUMBER'] || '000000')[0,6]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Determine the current branch
|
76
|
+
# returns: branch name
|
77
|
+
#
|
78
|
+
def self.current_branch
|
79
|
+
begin
|
80
|
+
`git rev-parse --abbrev-ref HEAD`.chomp
|
81
|
+
rescue
|
82
|
+
'master'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.gitflow_version(version)
|
87
|
+
return unless ENV.include?('BUILD_NUMBER')
|
88
|
+
version.special = gitflow_special
|
89
|
+
version
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.build_number
|
93
|
+
ENV['BUILD_NUMBER'] || '0'
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.gitflow_special
|
97
|
+
prefix = special_prefix
|
98
|
+
return version.special if prefix == 'master'
|
99
|
+
|
100
|
+
"#{prefix}#{build_number}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.special_prefix
|
104
|
+
# TODO: There is a better way to do this.
|
105
|
+
branch_name = current_branch
|
106
|
+
return 'release' if branch_name.start_with? 'release/'
|
107
|
+
return 'hotfix' if branch_name.start_with? 'hotfix/'
|
108
|
+
return 'feature' if branch_name.start_with? 'feature/'
|
109
|
+
branch_name
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'physique/dsl'
|
2
|
+
require 'physique/tool_locator'
|
3
|
+
|
4
|
+
module Physique
|
5
|
+
class TasksBuilder
|
6
|
+
include Albacore::DSL
|
7
|
+
include Albacore::Logging
|
8
|
+
include Physique::ToolLocator
|
9
|
+
|
10
|
+
@subclasses = []
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :subclasses
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.inherited(subclass)
|
17
|
+
TasksBuilder.subclasses << subclass
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :solution
|
21
|
+
|
22
|
+
def self.build_tasks_for(solution)
|
23
|
+
TasksBuilder.subclasses.each do |builder_class|
|
24
|
+
builder_class.new.build_tasks_for solution
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_tasks_for(solution)
|
29
|
+
@solution = solution
|
30
|
+
build_tasks
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_tasks
|
34
|
+
raise 'This method must be implemented in your subclass'
|
35
|
+
end
|
36
|
+
|
37
|
+
def ensure_output_location(path)
|
38
|
+
# Ensure output directory exists
|
39
|
+
FileUtils.mkdir_p path
|
40
|
+
end
|
41
|
+
|
42
|
+
def namespace(name, &block)
|
43
|
+
name = to_string_or_symbol(name)
|
44
|
+
Rake.application.in_namespace(name, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_string_or_symbol(name)
|
48
|
+
name = name.to_s if name.kind_of?(Symbol)
|
49
|
+
name = name.to_str if name.respond_to?(:to_str)
|
50
|
+
unless name.kind_of?(String) || name.nil?
|
51
|
+
raise ArgumentError, 'Expected a String or Symbol for a namespace name'
|
52
|
+
end
|
53
|
+
name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Gem.find_files('physique/task_builders/*.rb').each { |path| require path }
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'map'
|
2
|
+
require 'albacore'
|
3
|
+
|
4
|
+
module Physique
|
5
|
+
module ToolLocator
|
6
|
+
include Albacore::Logging
|
7
|
+
|
8
|
+
# Allows you to locate a tool on disk given a file specification. For example...
|
9
|
+
#
|
10
|
+
# locate_tool 'C:/Program Files/Microsoft SQL Server/**/Tools/Binn/SQLCMD.EXE'
|
11
|
+
#
|
12
|
+
# The tool sorts any matching executables in descending order to that the most recent version is returned. To
|
13
|
+
# change this behavior call the method with the reverse option.
|
14
|
+
#
|
15
|
+
# locate_tool 'C:/path/to/**/tool.exe', reverse: false
|
16
|
+
#
|
17
|
+
# Throws a ToolNotFoundError if no tool could be found.
|
18
|
+
def locate_tool(paths, options = {})
|
19
|
+
# FileList only correctly handles forward-slashes, even on Windows
|
20
|
+
paths = paths.gsub('\\', '/')
|
21
|
+
|
22
|
+
info { "Extracting paths from the following pattern #{paths}" }
|
23
|
+
paths = FileList[paths] unless paths.respond_to?(:each)
|
24
|
+
|
25
|
+
info { "Attempting to locate tool in the following paths #{paths}" }
|
26
|
+
opts = Map.options(options)
|
27
|
+
opts = opts.apply :reverse => true
|
28
|
+
paths = paths.collect { |p| which(p) }.compact.sort
|
29
|
+
paths = paths.reverse if opts[:reverse]
|
30
|
+
tool = paths.first
|
31
|
+
|
32
|
+
raise ToolNotFoundError, "Could not find tool in the following paths: \n #{paths}" if tool.nil?
|
33
|
+
tool
|
34
|
+
end
|
35
|
+
|
36
|
+
def which(exe)
|
37
|
+
Albacore::CrossPlatformCmd.which(exe) ? exe : nil;
|
38
|
+
end
|
39
|
+
|
40
|
+
class ToolNotFoundError < Exception; end
|
41
|
+
end
|
42
|
+
end
|
data/physique.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'physique/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'physique'
|
8
|
+
spec.version = Physique::VERSION
|
9
|
+
spec.authors = ['Robert Scaduto']
|
10
|
+
spec.email = ['rscaduto@thirdwave.it']
|
11
|
+
spec.description = %q{Beautiful builds for .NET projects}
|
12
|
+
spec.summary = %q{A conventional build framework supporting NUnit, FluentMigrator and Octopus Deploy}
|
13
|
+
spec.homepage = 'http://github.com/scardetto/physique'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'rspec', '2.14.1'
|
23
|
+
spec.add_dependency 'activesupport', '~> 4.1'
|
24
|
+
spec.add_dependency 'map', '~> 6.5'
|
25
|
+
spec.add_dependency 'albacore', '2.0.0.rc.12'
|
26
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'physique'
|
2
|
+
|
3
|
+
describe Physique::FluentMigratorConfig do
|
4
|
+
it 'should find full project path when specifying the name and language' do
|
5
|
+
project_name = 'Test.Database'
|
6
|
+
opts = Physique::FluentMigratorConfig.new.tap { |c|
|
7
|
+
c.project = project_name
|
8
|
+
c.lang = :vb
|
9
|
+
}.opts
|
10
|
+
|
11
|
+
expect(opts.project_file).to eq("src/#{project_name}/#{project_name}.vbproj")
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should default to the cs programming language' do
|
15
|
+
project_name = 'Test.Database'
|
16
|
+
opts = Physique::FluentMigratorConfig.new.tap { |c|
|
17
|
+
c.project = project_name
|
18
|
+
}.opts
|
19
|
+
|
20
|
+
expect(opts.project_file).to eq("src/#{project_name}/#{project_name}.csproj")
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'physique/project'
|
2
|
+
|
3
|
+
describe Physique::Project do
|
4
|
+
it 'should echo the path when full project file name is provided' do
|
5
|
+
project_name = 'test.csproj'
|
6
|
+
expect(get_path(project_name)).to eq(project_name)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return the full path when partial project file name is provided' do
|
10
|
+
project_name = 'TestProject.Domain'
|
11
|
+
expect(get_path(project_name)).to eq("src/#{project_name}/#{project_name}.csproj")
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should handle multiple languages' do
|
15
|
+
project_name = 'TestProject.Domain'
|
16
|
+
language = 'vb'
|
17
|
+
expect(get_path(project_name, language)).to eq("src/#{project_name}/#{project_name}.vbproj")
|
18
|
+
|
19
|
+
language = 'fs'
|
20
|
+
expect(get_path(project_name, language)).to eq("src/#{project_name}/#{project_name}.fsproj")
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_path(name, ext = 'cs')
|
24
|
+
::Physique::Project.get_path(name, ext)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'physique'
|
2
|
+
|
3
|
+
describe Physique::CompileConfig do
|
4
|
+
|
5
|
+
describe 'By default' do
|
6
|
+
before(:all) { @config = Physique::CompileConfig.new }
|
7
|
+
|
8
|
+
it 'should set the build configuration to Release' do
|
9
|
+
expect(@config.opts.configuration).to eq('Release')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/spec/sqlcmd_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'physique'
|
2
|
+
require 'physique/tasks/sqlcmd'
|
3
|
+
|
4
|
+
describe Physique::SqlCmd::Config do
|
5
|
+
if ::Rake::Win32.windows?
|
6
|
+
describe 'When initialized with the minimum required values' do
|
7
|
+
before(:all) do
|
8
|
+
@opts = Physique::SqlCmd::Config.new.tap { |c|
|
9
|
+
c.server_name = 'server'
|
10
|
+
c.command = 'command'
|
11
|
+
}.opts
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should find sqlcmd tool' do
|
15
|
+
expect(@opts[:exe]).to match(/sqlcmd/i)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should break on errors' do
|
19
|
+
expect(@opts[:continue_on_errors]).to be_false
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should set the server name' do
|
23
|
+
expect(@opts[:server_name]).to eq('server')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'When initialized with a command' do
|
28
|
+
before(:all) do
|
29
|
+
@opts = Physique::SqlCmd::Config.new.tap { |c|
|
30
|
+
c.server_name = 'server'
|
31
|
+
c.command = 'command'
|
32
|
+
}.opts
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should set the command' do
|
36
|
+
expect(@opts[:command]).to eq('command')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should set the source to :command' do
|
40
|
+
expect(@opts[:source]).to eq(:command)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'When initialized with a file' do
|
45
|
+
before(:all) do
|
46
|
+
@opts = Physique::SqlCmd::Config.new.tap { |c|
|
47
|
+
c.server_name = 'server'
|
48
|
+
c.file = 'test.sql'
|
49
|
+
}.opts
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should set the file' do
|
53
|
+
expect(@opts[:file]).to eq('test.sql')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should set the source to :file' do
|
57
|
+
expect(@opts[:source]).to eq(:file)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'When initialized with both a file and a command' do
|
62
|
+
before(:all) do
|
63
|
+
@opts = Physique::SqlCmd::Config.new.tap { |c|
|
64
|
+
c.server_name = 'server'
|
65
|
+
c.command = 'command'
|
66
|
+
c.file = 'file'
|
67
|
+
}.opts
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should give precedence to the command' do
|
71
|
+
expect(@opts[:source]).to eq(:command)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Physique::SqlCmd::Cmd do
|
78
|
+
describe 'When configured with a file' do
|
79
|
+
before(:all) do
|
80
|
+
opts = Physique::SqlCmd::Config.new.tap { |c|
|
81
|
+
c.server_name = 'server'
|
82
|
+
c.database_name = 'database'
|
83
|
+
c.file = 'test.sql'
|
84
|
+
}.opts
|
85
|
+
|
86
|
+
@cmd = Physique::SqlCmd::Cmd.new opts
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should break on errors' do
|
90
|
+
expect(@cmd.parameters).to include('-b')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should include the server name' do
|
94
|
+
expect(@cmd.parameters).to include('-S server')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should include the database name' do
|
98
|
+
expect(@cmd.parameters).to include('-d database')
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should include the file name' do
|
102
|
+
expect(@cmd.parameters).to include('-i test.sql')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'When configured with a command' do
|
107
|
+
before(:all) do
|
108
|
+
opts = Physique::SqlCmd::Config.new.tap { |c|
|
109
|
+
c.server_name = 'server'
|
110
|
+
c.command = 'command'
|
111
|
+
}.opts
|
112
|
+
|
113
|
+
@cmd = Physique::SqlCmd::Cmd.new opts
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should break on errors' do
|
117
|
+
expect(@cmd.parameters).to include('-b')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should include the server name' do
|
121
|
+
expect(@cmd.parameters).to include('-S server')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should include the command in single quotes' do
|
125
|
+
expect(@cmd.parameters).to include("-Q 'command'")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe 'When setting variables' do
|
130
|
+
before(:all) do
|
131
|
+
opts = Physique::SqlCmd::Config.new.tap { |c|
|
132
|
+
c.server_name = 'server'
|
133
|
+
c.command = 'command'
|
134
|
+
c.set_variable 'test_variable1', 'test_value1'
|
135
|
+
c.set_variable 'test_variable2', 'test_value2'
|
136
|
+
}.opts
|
137
|
+
|
138
|
+
@cmd = Physique::SqlCmd::Cmd.new opts
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should add multiple variables to the command line' do
|
142
|
+
expect(@cmd.parameters).to include("-v test_variable1=test_value1")
|
143
|
+
expect(@cmd.parameters).to include("-v test_variable2=test_value2")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|