Schlagwort-Archive: YouTrack

Anwender durch zielgerichtete Release Notes in die Produktentwicklung integrieren

In diesem Video zeige ich eine von vielen maßgeschneiderten Funktionen unseres Release Prozesses. Das Ziel dabei war es die Anwender noch mehr in die Produktentwicklung einzubinden.

Die langfristige Vision: Anwender bringen selbst die Anforderungen ein. Wie das genau gemeint ist und wie wir das umgesetzt haben, seht ihr im Video. Unter anderem kommen YouTrack und TeamCity zum Einsatz.

 

Über ein Rake-Skript, welches auf ein bereits existierendes YouTrack-Gem zurückgreift, sprechen wir die Rest-API an. Vielen Dank an Alexander Groß von GROSSWEBER für die Hilfe bei der Umsetzung unserer Vision.

require 'youtrack'
require 'ostruct'
module Build
class YouTrack
class View
attr_reader :issues, :by_department, :by_relevance
def initialize(issues)
@issues = issues
@by_department = department(issues)
@by_relevance = relevance(issues)
end
private
def department(issues)
create_view(issues, proc { |issue| issue.departments })
end
def relevance(issues)
create_view(issues, proc { |issue| issue.relevant_to })
end
def create_view(issues, group_by)
view = issues.inject({}) do |memo, issue|
group_by.call(issue).each do |rel|
previous_value = memo.fetch(rel, [])
new_value = previous_value << issue
memo[rel] = new_value.sort_by(&:issue_id)
end
memo
end
Hash[view.sort]
end
end
class << self
NOT_FOUND = proc { { 'value' => nil } }
def fixed_issues(from, to)
resource = client.issues
maybe_patch_unreleased_methods(resource)
query = query(from, to)
puts "Getting issue list from YouTrack using query: #{query}"
issues = resource.list(filter: query, max: 1000)
issues = force_list(issues)
transformed = transform(issues)
View.new(transformed)
end
private
def client
@client ||= Youtrack::Client.new do |c|
c.url = 'your-url'
c.login = 'your-user'
c.password = 'your-pw'
c.connect!
end
end
def maybe_patch_unreleased_methods(issues)
return if issues.respond_to?(:list)
warn 'Patching #list method'
# Get a list of issues for a search query.
#
# attributes
# filter string A query to search for issues.
# with string List of fields that should be included in the result.
# max integer Maximum number of issues to get. If not provided, only 10 issues will be returned by default.
# after integer A number of issues to skip before getting a list of issues.
#
def issues.list(attributes = {})
attributes[:max] ||= 10
get("issue?#{URI.encode_www_form(attributes)}")
end
end
def query(from, to)
"project: HECO_comWORK Fixed in build: #{from} .. #{to} Department: -KEINE #{excluded_subsystems}"
end
def excluded_subsystems
spec = ENV['RELEASE_NOTES_EXCLUDE_SUBSYSTEMS']
return unless spec
spec = spec.split(',')
return if spec.empty?
"Subsystem: #{spec.map { |s| "-{#{s}}" }.join(' ')}"
end
def force_list(issues)
issues = issues.to_hash['issueCompacts']['issue'] rescue []
([] << issues).flatten(1)
end
def transform(issues)
issues.map do |x|
field = x['field']
project = field.find { |f| f['name'] == 'projectShortName' }['value']
number = field.find { |f| f['name'] == 'numberInProject' }['value']
issue_id = "#{project}-#{number}"
subsystem = subsystem(field)
summary = field.find { |f| f['name'] == 'summary' }['value']
info = field.find(NOT_FOUND) { |f| f['name'] == 'Release Infotext' }['value']
departments = arrayify(field, 'Department')
relevant_to = arrayify(field, 'Relevant to')
OpenStruct.new(issue_id: issue_id,
subsystem: subsystem,
summary: summary,
info: info,
departments: departments,
relevant_to: relevant_to)
end
end
def subsystem(field)
value = field.find { |f| f['name'] == 'Subsystem' }['value']
return nil if value == 'No Subsystem'
value
end
def arrayify(field, key)
value = field.find(NOT_FOUND) { |f| f['name'] == key }['value']
return [] if value.nil?
([value]).flatten.sort
end
end
end
end
view raw youtrack.rb hosted with ❤ by GitHub

Wer weitere Einblicke in unseren Prozess bekommen möchte, der kann mir dazu einen Kommentar hinterlassen.

require 'youtrack'
require 'ostruct'
module Build
class YouTrack
class View
attr_reader :issues, :by_department, :by_relevance
def initialize(issues)
@issues = issues
@by_department = department(issues)
@by_relevance = relevance(issues)
end
private
def department(issues)
create_view(issues, proc { |issue| issue.departments })
end
def relevance(issues)
create_view(issues, proc { |issue| issue.relevant_to })
end
def create_view(issues, group_by)
view = issues.inject({}) do |memo, issue|
group_by.call(issue).each do |rel|
previous_value = memo.fetch(rel, [])
new_value = previous_value << issue
memo[rel] = new_value.sort_by(&:issue_id)
end
memo
end
Hash[view.sort]
end
end
class << self
NOT_FOUND = proc { { 'value' => nil } }
def fixed_issues(from, to)
resource = client.issues
maybe_patch_unreleased_methods(resource)
query = query(from, to)
puts "Getting issue list from YouTrack using query: #{query}"
issues = resource.list(filter: query, max: 1000)
issues = force_list(issues)
transformed = transform(issues)
View.new(transformed)
end
private
def client
@client ||= Youtrack::Client.new do |c|
c.url = 'your-url'
c.login = 'your-user'
c.password = 'your-pw'
c.connect!
end
end
def maybe_patch_unreleased_methods(issues)
return if issues.respond_to?(:list)
warn 'Patching #list method'
# Get a list of issues for a search query.
#
# attributes
# filter string A query to search for issues.
# with string List of fields that should be included in the result.
# max integer Maximum number of issues to get. If not provided, only 10 issues will be returned by default.
# after integer A number of issues to skip before getting a list of issues.
#
def issues.list(attributes = {})
attributes[:max] ||= 10
get("issue?#{URI.encode_www_form(attributes)}")
end
end
def query(from, to)
"project: HECO_comWORK Fixed in build: #{from} .. #{to} Department: -KEINE #{excluded_subsystems}"
end
def excluded_subsystems
spec = ENV['RELEASE_NOTES_EXCLUDE_SUBSYSTEMS']
return unless spec
spec = spec.split(',')
return if spec.empty?
"Subsystem: #{spec.map { |s| "-{#{s}}" }.join(' ')}"
end
def force_list(issues)
issues = issues.to_hash['issueCompacts']['issue'] rescue []
([] << issues).flatten(1)
end
def transform(issues)
issues.map do |x|
field = x['field']
project = field.find { |f| f['name'] == 'projectShortName' }['value']
number = field.find { |f| f['name'] == 'numberInProject' }['value']
issue_id = "#{project}#{number}"
subsystem = subsystem(field)
summary = field.find { |f| f['name'] == 'summary' }['value']
info = field.find(NOT_FOUND) { |f| f['name'] == 'Release Infotext' }['value']
departments = arrayify(field, 'Department')
relevant_to = arrayify(field, 'Relevant to')
OpenStruct.new(issue_id: issue_id,
subsystem: subsystem,
summary: summary,
info: info,
departments: departments,
relevant_to: relevant_to)
end
end
def subsystem(field)
value = field.find { |f| f['name'] == 'Subsystem' }['value']
return nil if value == 'No Subsystem'
value
end
def arrayify(field, key)
value = field.find(NOT_FOUND) { |f| f['name'] == key }['value']
return [] if value.nil?
([value]).flatten.sort
end
end
end
end

view raw
youtrack.rb
hosted with ❤ by GitHub

require 'youtrack'
require 'ostruct'
module Build
class YouTrack
class View
attr_reader :issues, :by_department, :by_relevance
def initialize(issues)
@issues = issues
@by_department = department(issues)
@by_relevance = relevance(issues)
end
private
def department(issues)
create_view(issues, proc { |issue| issue.departments })
end
def relevance(issues)
create_view(issues, proc { |issue| issue.relevant_to })
end
def create_view(issues, group_by)
view = issues.inject({}) do |memo, issue|
group_by.call(issue).each do |rel|
previous_value = memo.fetch(rel, [])
new_value = previous_value << issue
memo[rel] = new_value.sort_by(&:issue_id)
end
memo
end
Hash[view.sort]
end
end
class << self
NOT_FOUND = proc { { 'value' => nil } }
def fixed_issues(from, to)
resource = client.issues
maybe_patch_unreleased_methods(resource)
query = query(from, to)
puts "Getting issue list from YouTrack using query: #{query}"
issues = resource.list(filter: query, max: 1000)
issues = force_list(issues)
transformed = transform(issues)
View.new(transformed)
end
private
def client
@client ||= Youtrack::Client.new do |c|
c.url = 'your-url'
c.login = 'your-user'
c.password = 'your-pw'
c.connect!
end
end
def maybe_patch_unreleased_methods(issues)
return if issues.respond_to?(:list)
warn 'Patching #list method'
# Get a list of issues for a search query.
#
# attributes
# filter string A query to search for issues.
# with string List of fields that should be included in the result.
# max integer Maximum number of issues to get. If not provided, only 10 issues will be returned by default.
# after integer A number of issues to skip before getting a list of issues.
#
def issues.list(attributes = {})
attributes[:max] ||= 10
get("issue?#{URI.encode_www_form(attributes)}")
end
end
def query(from, to)
"project: HECO_comWORK Fixed in build: #{from} .. #{to} Department: -KEINE #{excluded_subsystems}"
end
def excluded_subsystems
spec = ENV['RELEASE_NOTES_EXCLUDE_SUBSYSTEMS']
return unless spec
spec = spec.split(',')
return if spec.empty?
"Subsystem: #{spec.map { |s| "-{#{s}}" }.join(' ')}"
end
def force_list(issues)
issues = issues.to_hash['issueCompacts']['issue'] rescue []
([] << issues).flatten(1)
end
def transform(issues)
issues.map do |x|
field = x['field']
project = field.find { |f| f['name'] == 'projectShortName' }['value']
number = field.find { |f| f['name'] == 'numberInProject' }['value']
issue_id = "#{project}#{number}"
subsystem = subsystem(field)
summary = field.find { |f| f['name'] == 'summary' }['value']
info = field.find(NOT_FOUND) { |f| f['name'] == 'Release Infotext' }['value']
departments = arrayify(field, 'Department')
relevant_to = arrayify(field, 'Relevant to')
OpenStruct.new(issue_id: issue_id,
subsystem: subsystem,
summary: summary,
info: info,
departments: departments,
relevant_to: relevant_to)
end
end
def subsystem(field)
value = field.find { |f| f['name'] == 'Subsystem' }['value']
return nil if value == 'No Subsystem'
value
end
def arrayify(field, key)
value = field.find(NOT_FOUND) { |f| f['name'] == key }['value']
return [] if value.nil?
([value]).flatten.sort
end
end
end
end

view raw
youtrack.rb
hosted with ❤ by GitHub

Where YouTrack 6 still lacks

  • Single Sign-on in a Windows Domain: Vote for this here
  • Print sprint cards: Vote for this here (or enhance the whole agile board)
  • Support of Skype IM for notifications: Vote for this here
  • Support of enum type fields as a dop-down in order to implement the Fibonacci sequence: Vote for this here
  • Summarize states into one column in Agile Board so that showing open and reopened issues is possible: Vote for this here
%d Bloggern gefällt das: