abak-flow 0.1.0

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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea/
6
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'hub', '~> 1.8.1'
6
+ gem 'commander', '~> 4.0.7'
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ Abak-flow
2
+ =========
3
+ Нет, это не новая идеология ведения проекта, это всего лишь набор утилит которые помогают связать использование git-flow и github
4
+
5
+ # Концепция
6
+ Идеология git-flow использует слудующий набор веток:
7
+
8
+ * *master* - всегда пригодна для развертывания
9
+ * *develop* - основная ветка разработки
10
+ * *hotfix* - ветка для изменений которые попадут на продакшен сервер
11
+ * *feature* - ветки для крупных задачь
12
+
13
+ Github-flow же наоборот ведет основную разработку в ветке master, но при этом master является пригодным для развертывания в любой момент.
14
+
15
+ После долгих раздумий было принято применить следующий набор правил, для разработки на github:
16
+
17
+ 1. Вся разработка любой задачи и функционала ведется только в ветках **feature**
18
+ 2. Разработаный функционал из ветки **feature** оформляется pull request только в ветку **develop**
19
+ 3. Все исправления ошибок, которые должны попасть на продакшен сервер делаются только в ветках **hotfix**
20
+ 4. Исправленные ошибки из ветки **hotfix** фофрмляются pull request только в ветку **master**
21
+ 5. После получения исправлений на текущий момент в репозитории инициируется merge ветки **master** в **develop**
22
+
23
+
24
+ # Установка
25
+ *в процессе*
26
+
27
+ # С чего начать?
28
+ $ git request help
29
+
30
+ # Примеры использования
31
+ *в процессе*
32
+
33
+ # В заключении
34
+ Данный репозиторий и изложенные в нем идеи ни в коем случае не претендуют на идеал и совершенство. Это всего лишь узко заточенная комбинация гемов
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/abak-flow.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'abak-flow/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'abak-flow'
7
+ s.version = Abak::Flow::VERSION
8
+ s.authors = ['Strech (aka Sergey Fedorov)']
9
+ s.email = ['oni.strech@gmail.com']
10
+ s.homepage = 'https://github.com/Strech/abak-flow'
11
+ s.summary = %q{Совмещение 2-х подходов разработки Git-flow & Github-flow}
12
+ s.description = %q{Простой набор правил и комманд, заточеных для работы в git-flow с использование в качестве удаленного репозитория github}
13
+
14
+ s.rubyforge_project = 'abak-flow'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_runtime_dependency 'hub'
22
+ s.add_runtime_dependency 'commander'
23
+ end
data/bin/request ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+ require 'abak-flow'
4
+ require "abak-flow/request"
data/lib/abak-flow.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'hub'
2
+ require 'abak-flow/hub_extensions'
3
+ require 'abak-flow/version'
4
+ require "commander/import"
@@ -0,0 +1,114 @@
1
+ module Abak::Flow
2
+ module RunnerExtension
3
+ def execute
4
+ if args.noop?
5
+ puts commands
6
+ elsif not args.skip?
7
+ if args.chained?
8
+ execute_command_chain
9
+ else
10
+ %x{#{args.to_exec.join(' ')}}
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ module CommandsExtension
17
+ def pull_request(args)
18
+ args.shift
19
+ options = { }
20
+ force = explicit_owner = false
21
+ base_project = local_repo.main_project
22
+ head_project = local_repo.current_project
23
+
24
+ from_github_ref = lambda do |ref, context_project|
25
+ if ref.index(':')
26
+ owner, ref = ref.split(':', 2)
27
+ project = github_project(context_project.name, owner)
28
+ end
29
+ [project || context_project, ref]
30
+ end
31
+
32
+ while arg = args.shift
33
+ case arg
34
+ when '-f'
35
+ force = true
36
+ when '-b'
37
+ base_project, options[:base] = from_github_ref.call(args.shift, base_project)
38
+ when '-h'
39
+ head = args.shift
40
+ explicit_owner = !!head.index(':')
41
+ head_project, options[:head] = from_github_ref.call(head, head_project)
42
+ when '-i'
43
+ options[:issue] = args.shift
44
+ when '-d'
45
+ options[:body] = args.shift
46
+ else
47
+ if url = resolve_github_url(arg) and url.project_path =~ /^issues\/(\d+)/
48
+ options[:issue] = $1
49
+ base_project = url.project
50
+ elsif !options[:title] then options[:title] = arg
51
+ else
52
+ abort "invalid argument: #{arg}"
53
+ end
54
+ end
55
+ end
56
+
57
+ options[:project] = base_project
58
+ options[:base] ||= master_branch.short_name
59
+
60
+ if tracked_branch = options[:head].nil? && current_branch.upstream
61
+ if base_project == head_project and tracked_branch.short_name == options[:base]
62
+ $stderr.puts "Aborted: head branch is the same as base (#{options[:base].inspect})"
63
+ warn "(use `-h <branch>` to specify an explicit pull request head)"
64
+ abort
65
+ end
66
+ end
67
+ options[:head] ||= (tracked_branch || current_branch).short_name
68
+
69
+ # when no tracking, assume remote branch is published under active user's fork
70
+ user = github_user(true, head_project.host)
71
+ if head_project.owner != user and !tracked_branch and !explicit_owner
72
+ head_project = head_project.owned_by(user)
73
+ end
74
+
75
+ remote_branch = "#{head_project.remote}/#{options[:head]}"
76
+ options[:head] = "#{head_project.owner}:#{options[:head]}"
77
+
78
+ if !force and tracked_branch and local_commits = git_command("rev-list --cherry #{remote_branch}...")
79
+ $stderr.puts "Aborted: #{local_commits.split("\n").size} commits are not yet pushed to #{remote_branch}"
80
+ warn "(use `-f` to force submit a pull request anyway)"
81
+ abort
82
+ end
83
+
84
+ if args.noop?
85
+ puts "Would reqest a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}"
86
+ exit
87
+ end
88
+
89
+ unless options[:title] or options[:issue]
90
+ base_branch = "#{base_project.remote}/#{options[:base]}"
91
+ changes = git_command "log --no-color --pretty=medium --cherry %s...%s" %
92
+ [base_branch, remote_branch]
93
+
94
+ options[:title], options[:body] = pullrequest_editmsg(changes) { |msg|
95
+ msg.puts "# Requesting a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}"
96
+ msg.puts "#"
97
+ msg.puts "# Write a message for this pull request. The first block"
98
+ msg.puts "# of text is the title and the rest is description."
99
+ }
100
+ end
101
+
102
+ pull = create_pullrequest(options)
103
+
104
+ args.executable = 'echo'
105
+ args.replace [pull['html_url']]
106
+ rescue HTTPExceptions
107
+ display_http_exception("creating pull request", $!.response)
108
+ exit 1
109
+ end
110
+ end
111
+
112
+ Hub::Runner.send :include, RunnerExtension
113
+ Hub::Commands.send :include, CommandsExtension
114
+ end
@@ -0,0 +1,123 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Abak::Flow
3
+ # @TODO Сделать класс, в котором собрать общие куски из задач
4
+
5
+ program :name, 'Утилита для оформления pull request на github.com'
6
+ program :version, '0.0.1'
7
+ program :description, 'Утилита, заточенная под git-flow но с использованием github.com'
8
+
9
+ default_command :help
10
+ command :publish do |c|
11
+ c.syntax = 'git request publish <Заголовок>'
12
+ c.description = 'Оформить pull request из текущей ветки (feature -> develop, hotfix -> master)'
13
+
14
+ # Опции нужны, если человек хочет запушить ветку, с именем отличным от стандарта
15
+ c.option '--head STRING', String, 'Имя ветки, которую нужно принять в качестве изменений'
16
+ c.option '--base STRING', String, 'Имя ветки, в которую нужно принять изменения'
17
+
18
+ c.action do |args, options|
19
+ repository = Hub::Commands.send :local_repo
20
+ current_branch = repository.current_branch.short_name
21
+ request_rules = {
22
+ :feature => :develop,
23
+ :hotfix => :master
24
+ }
25
+ jira_browse_url = 'http://jira.dev.apress.ru/browse/'
26
+
27
+ # Проверим, что мы не в мастере или девелопе
28
+ if [:master, :develop].include? current_branch.to_sym
29
+ say 'Нельзя делать pull request из меток master или develop'
30
+ exit
31
+ end
32
+
33
+ # Проверим, что у нас настроен upstream
34
+ if repository.remote_by_name('upstream').nil?
35
+ say 'Необходимо настроить репозиторий upstream (главный) для текущего пользователя'
36
+ say '=> git remote add upstream https://Developer@github.com/abak-press/sample.git'
37
+ exit
38
+ end
39
+
40
+ if args.first.to_s.empty?
41
+ say 'Пожалуйста, укажите в заголовке номер вашей задачи, например так:'
42
+ say '=> git request "PC-001"'
43
+ exit
44
+ end
45
+
46
+ # Расставим ветки согласно правилам
47
+ remote_branch, task = current_branch.split('/').push(nil).map(&:to_s)
48
+ head = "#{repository.repo_owner}:#{current_branch}"
49
+ base = "#{repository.remote_by_name('upstream').project.owner}:#{request_rules.fetch(remote_branch.to_sym, '')}"
50
+
51
+ head = options.head unless options.head.nil?
52
+ base = options.base unless options.base.nil?
53
+
54
+ # Запушим текущую ветку на origin
55
+ # @TODO Может быть лучше достать дерективу конфига origin?
56
+ say "=> Обновляю ветку #{current_branch} на origin"
57
+ Hub::Runner.execute('push', repository.main_project.remote.name, current_branch)
58
+
59
+ # Запостим pull request на upstream
60
+ command_options = ['pull-request', args.first, '-b', base, '-h', head, '-d']
61
+ command_options |= ['-d', jira_browse_url + task] if task =~ /^\w+\-\d{1,}$/
62
+
63
+ say '=> Делаю pull request на upstream'
64
+ say Hub::Runner.execute(*command_options)
65
+ end
66
+ end
67
+
68
+ command :update do |c|
69
+ c.syntax = 'git request update'
70
+ c.description = 'Обновить ветку на удаленном (origin) репозитории'
71
+
72
+ c.option '--branch STRING', String, 'Имя ветки, которую нужно обновить'
73
+
74
+ c.action do |args, options|
75
+ repository = Hub::Commands.send :local_repo
76
+ current_branch = repository.current_branch.short_name
77
+
78
+ # Запушим текущую ветку на origin
79
+ branch = options.branch || current_branch
80
+ say "=> Обновляю ветку #{branch} на origin"
81
+ Hub::Runner.execute('push', repository.main_project.remote.name, branch)
82
+ end
83
+ end
84
+
85
+ command :done do |c|
86
+ c.syntax = 'git request done'
87
+ c.description = 'Завершить pull request. По умолчанию удаляются ветки как локальная (local), так и удаленная (origin)'
88
+
89
+ c.option '--branch STRING', String, 'Имя ветки pull request которой нужно закрыть'
90
+ c.option '--all', 'Удаляет ветку в локальном репозитории и в удалнном (local + origin) (по умолчанию)'
91
+ c.option '--local', 'Удаляет ветку только в локальном репозитории (local)'
92
+ c.option '--origin', 'Удаляет ветку в удаленном репозитории (origin)'
93
+
94
+ c.action do |args, options|
95
+ repository = Hub::Commands.send :local_repo
96
+ current_branch = repository.current_branch.short_name
97
+ branch = options.branch || current_branch
98
+
99
+ type = :all
100
+ if [options.local, options.origin].compact.count == 1
101
+ type = options.local ? :local : :origin
102
+ end
103
+
104
+ warning = "Внимание! Alarm! Danger! Achtung\nЕсли вы удалите ветку на удаленном репозитории, а ваш pull request еще не приняли, вы рискуете потерять проделанную работу.\nВы уверены, что хотите продолжить?"
105
+ if [:all, :origin].include?(type)
106
+ say '=> Вы приняли верное решение :)' && exit unless agree("#{warning} [yes/no/y/n]:")
107
+ end
108
+
109
+ if [:all, :origin].include? type
110
+ say "=> Удаляю ветку #{branch} на origin"
111
+ Hub::Runner.execute('push', repository.main_project.remote.name, ':' + branch)
112
+ end
113
+
114
+ if [:all, :local].include? type
115
+ remote_branch, task = current_branch.split('/').push(nil).map(&:to_s)
116
+
117
+ say "=> Удаляю локальную ветку #{branch}"
118
+ Hub::Runner.execute('checkout', 'develop')
119
+ Hub::Runner.execute('branch', '-D', branch)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,5 @@
1
+ module Abak
2
+ module Flow
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: abak-flow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Strech (aka Sergey Fedorov)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-04 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hub
16
+ requirement: &70279720232900 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70279720232900
25
+ - !ruby/object:Gem::Dependency
26
+ name: commander
27
+ requirement: &70279720232480 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70279720232480
36
+ description: Простой набор правил и комманд, заточеных для работы в git-flow с использование
37
+ в качестве удаленного репозитория github
38
+ email:
39
+ - oni.strech@gmail.com
40
+ executables:
41
+ - request
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - .gitignore
46
+ - Gemfile
47
+ - README.md
48
+ - Rakefile
49
+ - VERSION
50
+ - abak-flow.gemspec
51
+ - bin/request
52
+ - lib/abak-flow.rb
53
+ - lib/abak-flow/hub_extensions.rb
54
+ - lib/abak-flow/request.rb
55
+ - lib/abak-flow/version.rb
56
+ homepage: https://github.com/Strech/abak-flow
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: abak-flow
76
+ rubygems_version: 1.8.10
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Совмещение 2-х подходов разработки Git-flow & Github-flow
80
+ test_files: []