changeset 5:d2efec56373f

working buglist transform and bugs fetching
author cin
date Tue, 01 Sep 2015 19:47:30 +0300
parents f8f966388b68
children 2a5f38eb25a9
files bug-list.xsl translate.pl
diffstat 2 files changed, 344 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/bug-list.xsl	Mon Aug 24 20:50:23 2015 +0300
+++ b/bug-list.xsl	Tue Sep 01 19:47:30 2015 +0300
@@ -4,6 +4,19 @@
 	extension-element-prefixes="exsl">
 	<xsl:output method="text" indent="yes" />
 
+	<!-- PARAMETERS -->
+
+	<!-- chargeset - название аккаунта, на который вести расходы -->
+	<xsl:param name="chargeset" />
+
+	<!-- root_task_id - id корневой задачи, в которую будут организованы все 
+		задачи -->
+	<xsl:param name="root_task_id" />
+
+	<!-- root_task - описание корневой задачи -->
+	<xsl:param name="root_task" />
+
+	<!-- GLOBAL VARIABLES -->
 	<xsl:variable name="resources"
 		select="document('resources.xml')/resources/resource" />
 
@@ -22,7 +35,7 @@
 		<xsl:element name="bug">
 			<xsl:attribute name="id"><xsl:value-of select="bug_id" /></xsl:attribute>
 			<xsl:if test="component = 'product' or not(number(estimated_time))">
-				<xsl:attribute name="product"><xsl:value-of select="boolean(1)" /></xsl:attribute>
+				<xsl:attribute name="group"><xsl:value-of select="boolean(1)" /></xsl:attribute>
 			</xsl:if>
 			<xsl:for-each select="dependson">
 				<xsl:apply-templates mode="tree" select="key('bugid', .)" />
@@ -48,11 +61,11 @@
 		<xsl:variable name="bugid" select="@id" />
 		<xsl:variable name="path" select="ancestor::bug" />
 		<xsl:variable name="level" select="count($path)" />
-		<xsl:for-each select="$path[@product]">
+		<xsl:for-each select="$path[@group]">
 			<xsl:variable name="pos" select="position()" />
 			<xsl:variable name="rank" select="$level - $pos" />
 			<rel container="{@id}" rank="{$rank}" level="{$level}">
-				<xsl:for-each select="$path[position() >= $pos and @product]">
+				<xsl:for-each select="$path[position() >= $pos and @group]">
 					<bug id="{@id}" />
 				</xsl:for-each>
 			</rel>
@@ -74,62 +87,123 @@
 	</xsl:template>
 
 	<xsl:variable name="structure">
-		<xsl:apply-templates select="$roots" mode="structure" />
+		<xsl:choose>
+			<xsl:when test="$root_task">
+				<bug id="_root" desc="{$root_task}" group="true">
+					<xsl:apply-templates select="$roots" mode="structure"/>
+				</bug>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:apply-templates select="$roots" mode="structure"/>
+			</xsl:otherwise>
+		</xsl:choose>
 	</xsl:variable>
 
 	<xsl:template match="bug" mode="structure">
 		<xsl:variable name="id" select="string(bug_id)" />
 		<xsl:variable name="self" select="." />
-		<bug id="{$id}">
-			<xsl:for-each select="exsl:node-set($parents)/bug[@parent = $id]">
-				<xsl:variable name="child" select="@id" />
-				<xsl:apply-templates select="$bugs[bug_id = $child]"
-					mode="structure" />
-			</xsl:for-each>
+		<xsl:variable name="children"
+			select="exsl:node-set($parents)/bug[@parent = $id]" />
+		<xsl:element name="bug">
+			<xsl:attribute name="id"><xsl:value-of select="$id" /></xsl:attribute>
+			<xsl:attribute name="desc"><xsl:value-of select="short_desc" /></xsl:attribute>
+
+			<xsl:if test="$children">
+				<xsl:attribute name="group"><xsl:value-of select="boolean($children)" /></xsl:attribute>
+
+				<xsl:for-each select="$children">
+					<xsl:variable name="child" select="@id" />
+					<xsl:apply-templates select="$bugs[bug_id = $child]"
+						mode="structure" />
+				</xsl:for-each>
+
+			</xsl:if>
+
+			<!-- filter out dependencies -->
 			<xsl:variable name="dependencies"
 				select="dependson[not(text() = exsl:node-set($parents)/bug[@parent = $id]/@id)]" />
-			<xsl:if test="$dependencies">
-				<depends>
-					<xsl:for-each select="$dependencies">
-						<bug id="{.}" />
-					</xsl:for-each>
-				</depends>
-			</xsl:if>
-		</bug>
+			<xsl:for-each select="$dependencies">
+				<dependency id="{.}" />
+			</xsl:for-each>
+		</xsl:element>
 	</xsl:template>
 
 	<!-- output -->
 	<xsl:template match="/">
 		<xsl:apply-templates select="exsl:node-set($structure)/bug">
 			<xsl:with-param name="indent" select="0" />
+			<xsl:with-param name="chargeset" select="$chargeset"/>
 		</xsl:apply-templates>
 	</xsl:template>
 
 	<xsl:template match="bug">
 		<xsl:param name="indent" select="0" />
+		<xsl:param name="chargeset" />
 		<xsl:variable name="id" select="@id" />
 		<xsl:variable name="details" select="$bugs[bug_id = $id]" />
+
+		<!-- task header -->
 		<xsl:call-template name="start-task">
 			<xsl:with-param name="indent" select="$indent" />
-			<xsl:with-param name="id" select="@id" />
-			<xsl:with-param name="desc" select="$details/short_desc" />
+			<xsl:with-param name="id">
+				<xsl:call-template name="bug-local-name">
+					<xsl:with-param name="id" select="@id" />
+				</xsl:call-template>
+			</xsl:with-param>
+			<xsl:with-param name="desc" select="@desc" />
 		</xsl:call-template>
+		
+		<xsl:if test="$chargeset">
+			<xsl:call-template name="println">
+				<xsl:with-param name="indent" select="$indent + 1"/>
+				<xsl:with-param name="text" select="concat('chargeset ', $chargeset)"/>
+			</xsl:call-template>
+		</xsl:if>
+
+		<!-- task details -->
+		<xsl:choose>
+			<xsl:when test="@group">
+				<!-- DEBUG -->
+				<xsl:call-template name="comment">
+					<xsl:with-param name="indent" select="$indent + 1" />
+					<xsl:with-param name="comment" select="'group'" />
+				</xsl:call-template>
+
 
-		<xsl:for-each select="$details/*">
-			<xsl:variable name="directive">
-				<xsl:apply-templates select="." mode="task-details" />
-			</xsl:variable>
-			<xsl:if test="string($directive)">
-				<xsl:call-template name="begin-line">
+				<xsl:apply-templates select="$details/node()"
+					mode="group-details">
 					<xsl:with-param name="indent" select="$indent + 1" />
-				</xsl:call-template>
-				<xsl:value-of select="$directive" />
-				<xsl:call-template name="end-line" />
-			</xsl:if>
-		</xsl:for-each>
+				</xsl:apply-templates>
 
+				<xsl:if
+					test="number($details/estimated_time) or number($details/actual_time) or number($details/remaining_time)">
+					<xsl:call-template name="start-task">
+						<xsl:with-param name="indent" select="$indent + 1" />
+						<xsl:with-param name="id" select="'manage'" />
+						<xsl:with-param name="desc" select="@desc" />
+					</xsl:call-template>
+					<xsl:apply-templates
+						select="$details/estimated_time | $details/actual_time | $details/remaining_time | $details/assigned_to"
+						mode="task-details">
+						<xsl:with-param name="indent" select="$indent + 2" />
+					</xsl:apply-templates>
+					<xsl:call-template name="end-task">
+						<xsl:with-param name="indent" select="$indent + 1" />
+					</xsl:call-template>
+				</xsl:if>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:apply-templates select="$details/node()"
+					mode="task-details">
+					<xsl:with-param name="indent" select="$indent + 1" />
+				</xsl:apply-templates>
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<!-- subtasks and dependencies -->
 		<xsl:apply-templates>
 			<xsl:with-param name="indent" select="$indent + 1" />
+			<xsl:with-param name="referer" select="." />
 		</xsl:apply-templates>
 
 		<xsl:call-template name="end-task">
@@ -137,47 +211,66 @@
 		</xsl:call-template>
 	</xsl:template>
 
+	<xsl:template match="dependency">
+		<xsl:param name="indent" />
+		<xsl:param name="referer" />
+		<xsl:call-template name="println">
+			<xsl:with-param name="indent" select="$indent" />
+			<xsl:with-param name="text">
+				<xsl:text>depends </xsl:text>
+				<xsl:call-template name="bug-reference">
+					<xsl:with-param name="id" select="@id" />
+					<xsl:with-param name="referer" select="$referer" />
+				</xsl:call-template>
+			</xsl:with-param>
+		</xsl:call-template>
+	</xsl:template>
+
+
+	<xsl:template match="text()" />
+
+	<!-- TASK ATTRIBUTES -->
+
 	<xsl:template match="estimated_time" mode="task-details">
+		<xsl:param name="indent" />
 		<xsl:if test="number(.)">
-			<xsl:value-of select="concat('effort ', .,'h')" />
+			<xsl:call-template name="println">
+				<xsl:with-param name="indent" select="$indent" />
+				<xsl:with-param name="text" select="concat('effort ', .,'h')" />
+			</xsl:call-template>
 		</xsl:if>
 	</xsl:template>
 
 	<xsl:template match="assigned_to" mode="task-details">
+		<xsl:param name="indent" />
 		<xsl:variable name="email" select="string(.)" />
 		<xsl:variable name="resource" select="$resources[@email = $email]/@id" />
 		<xsl:if test="$resource">
-			<xsl:value-of select="concat('allocate ', $resource)" />
+			<xsl:call-template name="println">
+				<xsl:with-param name="indent" select="$indent" />
+				<xsl:with-param name="text" select="concat('allocate ', $resource)" />
+			</xsl:call-template>
 		</xsl:if>
 	</xsl:template>
 	<xsl:template match="text()" mode="task-details">
 	</xsl:template>
 
-	<xsl:template match="depends">
-		<xsl:param name="indent" select="0" />
-		<xsl:call-template name="begin-line">
-			<xsl:with-param name="indent" select="$indent" />
-		</xsl:call-template>
-		<xsl:text>depends </xsl:text>
-		<xsl:apply-templates>
-			<xsl:with-param name="referer" select=".." />
-		</xsl:apply-templates>
-		<xsl:call-template name="end-line" />
+	<xsl:template match="assigned_to" mode="group-details">
+		<xsl:param name="indent" />
+		<xsl:variable name="email" select="string(.)" />
+		<xsl:variable name="resource" select="$resources[@email = $email]/@id" />
+		<xsl:if test="$resource">
+			<xsl:call-template name="println">
+				<xsl:with-param name="indent" select="$indent" />
+				<xsl:with-param name="text"
+					select="concat('responsible ', $resource)" />
+			</xsl:call-template>
+		</xsl:if>
+	</xsl:template>
+	<xsl:template match="text()" mode="group-details">
 	</xsl:template>
 
-	<xsl:template match="depends/bug">
-		<xsl:param name="referer" />
-		<xsl:call-template name="bug-reference">
-			<xsl:with-param name="id" select="@id" />
-			<xsl:with-param name="referer" select="$referer" />
-		</xsl:call-template>
-		<xsl:if test="position() != last()">
-			<xsl:text>, </xsl:text>
-		</xsl:if>
-	</xsl:template>
-
-
-	<xsl:template match="text()" />
+	<!-- PRIMITIVES -->
 
 
 
@@ -200,7 +293,7 @@
 		<xsl:variable name="targetPathFragment">
 			<bug id="#root" />
 			<xsl:for-each
-				select="exsl:node-set($structure)//bug[local-name(..) != 'depends' and @id = $id]/ancestor-or-self::bug">
+				select="exsl:node-set($structure)//bug[@id = $id]/ancestor-or-self::bug">
 				<bug id="{@id}" />
 			</xsl:for-each>
 		</xsl:variable>
@@ -250,9 +343,7 @@
 			<xsl:with-param name="indent" select="$indent" />
 		</xsl:call-template>
 		<xsl:text>task </xsl:text>
-		<xsl:call-template name="bug-local-name">
-			<xsl:with-param name="id" select="$id" />
-		</xsl:call-template>
+		<xsl:value-of select="$id" />
 		<xsl:value-of select="concat(' &quot;',$desc,'&quot; {')" />
 		<xsl:call-template name="end-line" />
 	</xsl:template>
@@ -275,6 +366,7 @@
 			</xsl:call-template>
 		</xsl:if>
 	</xsl:template>
+
 	<xsl:template name="end-line">
 		<xsl:text>&#xa;</xsl:text>
 	</xsl:template>
@@ -291,4 +383,26 @@
 			</xsl:call-template>
 		</xsl:if>
 	</xsl:template>
+
+	<xsl:template name="comment">
+		<xsl:param name="indent" />
+		<xsl:param name="comment" />
+		<xsl:call-template name="println">
+			<xsl:with-param name="indent" select="$indent" />
+			<xsl:with-param name="text">
+				<xsl:text># </xsl:text>
+				<xsl:value-of select="$comment" />
+			</xsl:with-param>
+		</xsl:call-template>
+	</xsl:template>
+
+	<xsl:template name="println">
+		<xsl:param name="indent" />
+		<xsl:param name="text" />
+		<xsl:call-template name="begin-line">
+			<xsl:with-param name="indent" select="$indent" />
+		</xsl:call-template>
+		<xsl:value-of select="$text" />
+		<xsl:call-template name="end-line" />
+	</xsl:template>
 </xsl:stylesheet>
\ No newline at end of file
--- a/translate.pl	Mon Aug 24 20:50:23 2015 +0300
+++ b/translate.pl	Tue Sep 01 19:47:30 2015 +0300
@@ -1,5 +1,11 @@
 #!/usr/bin/perl -w
 
+use JSON;
+use YAML::XS qw(LoadFile Dump);
+use URI;
+use XML::Writer;
+use IPC::Run qw(run);
+
 our @ClassPath = qw(
   /usr/share/java/xalan-j2-serializer.jar
   /usr/share/java/xalan-j2.jar
@@ -8,18 +14,175 @@
   .
 );
 
-xalan(
-	-IN          => "bug-list1.xml",
-	-XSL         => "bug-list.xsl",
-	-URIRESOLVER => "org.apache.xml.resolver.tools.CatalogResolver",
-	-ENTITYRESOLVER => "org.apache.xml.resolver.tools.CatalogResolver"
+my $config = LoadFile("config.yaml");
+
+if ( !( $config->{bugzilla}{url} =~ /\/$/ ) ) {
+	$config->{bugzilla}{url} .= "/";
+}
+
+my $bz = BzRest->new(
+	url    => $config->{bugzilla}{url},
+	apikey => $config->{bugzilla}{apikey}
+);
+
+my $bugs = $bz->GetBugs( { ids => [ 283, 284 ] } );
+
+my @fields = qw(
+    id
+    creation_time
+    last_change_time
+    creator
+    assigned_to
+    
+    status
+    resolution
+    
+    priority
+    severity
+    url
+    
+    blocks
+    depends_on
+    cc
+    
+    component
+    product
+    classification
+    version
+    
+    actual_time
+    estimated_time
+    remainig_time
+    deadline
+);
+
+my %fieldsMap = (
+	id => 'bug_id',
+	creator => 'reporter',
+	status => 'bug_status',
+	severity => 'bug_severity',
+	blocks => 'blocked',
+	depends_on => 'dependson',
+	creation_time => 'creation_ts',
+	last_change_time => 'delta_ts'
 );
 
+my $writer = XML::Writer->new( OUTPUT => \*STDOUT, ENCODING => 'utf-8' );
+
+$writer->xmlDecl("UTF-8");
+$writer->startTag("bugzilla");
+
+foreach my $bug ( @$bugs ) {
+	$writer->startTag("bug");
+	foreach my $field ( @fields ) {
+		next unless $bug->{$field};
+		
+		my $tagName = $fieldsMap{$field} || $field;
+		my @values = ref($bug->{$field}) && ref($bug->{$field}) eq 'ARRAY' ? @{$bug->{$field}} : $bug->{$field};
+		
+		foreach my $v (@values) {
+			$writer->dataElement($tagName, $v);
+		}
+	}
+	$writer->endTag();
+}
+
+$writer->endTag();
+
+
+
+#xalan(
+#	-IN          => "bug-list2.xml",
+#	-XSL         => "bug-list.xsl",
+#	-URIRESOLVER => "org.apache.xml.resolver.tools.CatalogResolver",
+#	-ENTITYRESOLVER => "org.apache.xml.resolver.tools.CatalogResolver",
+#	-PARAM => (chargeset => "dev")
+#);
+
 sub xalan {
-	my %params = @_;
+	my @params = @_;
 	return system 'java',
 	  -cp => join( ':', @ClassPath ),
-	  "org.apache.xalan.xslt.Process", %params;
+	  "org.apache.xalan.xslt.Process", @params;
+}
+
+package BzRest;
+use fields qw(url apikey);
+use LWP::UserAgent;
+use XMLRPC::Lite;
+use YAML::XS qw(Dump);
+
+use constant { SELF => __PACKAGE__ };
+
+sub new {
+	my $class = shift;
+	$class = ref $class || $class;
+
+	my $inst = fields::new($class);
+	$inst->CTOR(@_);
+
+	return $inst;
+}
+
+sub CTOR {
+	my SELF $this = shift;
+	my %params = @_;
+
+	$this->{url} = $params{url} or die "An url is required";
+	$this->{apikey} = $params{apikey} if $params{apikey};
+}
+
+sub GetBug {
+	my SELF $this = shift;
+	my $id        = shift;
+	my %params    = @_;
+
+	$params{api_key} = $this->{apikey};
+
+	my $bugurl = URI->new_abs( 'rest/bug/' . $id, $this->{url} );
+	$bugurl->query_form( \%params );
+
+	my $agent = LWP::UserAgent->new();
+	my $res   = $agent->get($bugurl);
+
+	return $this->_AssertResponse( $res, $bugurl );
+}
+
+sub GetBugs {
+	my SELF $this = shift;
+
+	return $this->CallXMLRPC( 'Bug.get', shift )->{bugs};
+}
+
+sub CallXMLRPC {
+	my SELF $this = shift;
+	my ( $method, $params ) = @_;
+
+	die "Method must be specified" unless $method;
+	$params ||= {};
+
+	$params->{api_key} = $this->{apikey};
+	my $url = URI->new_abs( 'xmlrpc.cgi', $this->{url} );
+
+	my $result = XMLRPC::Lite->proxy($url)->call( $method, $params );
+
+	die $result->fault if $result->fault;
+	return $result->result;
+}
+
+sub _AssertResponse {
+	my SELF $this = shift;
+	my ( $res, $url ) = @_;
+
+	die "Failed to get any response: " . $url unless $res;
+
+	die "Failed to fetch: " . $url . ": " . $res->code unless $res->is_success;
+
+	my $bug = JSON->new()->utf8()->decode( $res->content );
+
+	die "Bugzilla failed: " . $bug->{message} if $bug->{error};
+
+	return $bug->{bugs};
 }
 
 __END__