Project Reports & Websites

Steven J Zeil

Last modified: Mar 31, 2019
Contents:

1 Project Reports

1.1 Test Reports

We’ve already looked JUnit, which can be used to generate test reports like this one or this one.

This is generated in ant via the junitreport task:

junitreport.xml.listing
<project name="code2html" basedir="." default="build">

  <record name="ant.log" action="start" append="false" />

  <taskdef classpath="JFlex.jar" classname="JFlex.anttask.JFlexTask" name="jflex" />
	
  <echo>loading build-${os.name}.paths</echo>
  <include file="build-${os.name}.paths"/>
	

  <target name="generateSource">
    <mkdir dir="src/main/java"/>
    <jflex file="src/main/jflex/code2html.flex"
	   destdir="src/main/java"/>
  	<jflex file="src/main/jflex/code2tex.flex"
  	       destdir="src/main/java"/>
    <jflex file="src/main/jflex/list2html.flex"
	   destdir="src/main/java"/>
  	<jflex file="src/main/jflex/list2tex.flex"
  	       destdir="src/main/java"/>
  </target>
  

  <target name="compile" depends="generateSource">
    <mkdir dir="target/classes"/>
    <javac srcdir="src/main/java" destdir="target/classes"
	   source="1.6" includeantruntime="false"/>
  </target>

  <target name="compile-tests" depends="compile">
    <mkdir dir="target/test-classes"/>
    <javac srcdir="src/test/java" destdir="target/test-classes"
	   source="1.6" includeantruntime="false">
      <classpath refid="testCompilationPath"/>
    </javac>
  </target>

  <target name="test" depends="compile-tests">
  	<property name="mypath" refid="testExecutionPath"/>
  	<echo>testExecutioPath is ${mypath}</echo>
  	<echoproperties/>
    <mkdir dir="target/test-results/details"/>
    <junit printsummary="yes" 
	   haltonfailure="yes" fork="no"
	   >
        <classpath refid="testExecutionPath"/>
      <formatter type="xml"/>
      <batchtest todir="target/test-results/details">
	     <fileset dir="target/test-classes">
	        <include name="**/*Test*.class"/>
	     </fileset>
      </batchtest>
    </junit>
    <junitreport todir="target/test-results">
      <fileset dir="target/test-results/details">
        <include name="TEST-*.xml"/>
      </fileset>
      <report format="frames" todir="target/test-results/html"/>
    </junitreport>
  </target>

  <target name="build"  depends="test">
  	<jar destfile="codeAnnotation.jar" basedir="target/classes">
  	    <manifest>
  		    <attribute name="Main-Class"
  		               value="edu.odu.cs.code2html.Code2HTML"/>
  		</manifest>
  	</jar>
  </target>

  <target name="clean">
    <delete dir="target"/>
  </target>

  
</project>

or in Gradle via the java plugin.

1.2 Static Code Analyzers

Many tools that we will cover later for analyzing code can produce useful (or at least, impressive) documentation as a side effect.

1.3 Configuration Reports

Configuration managers (to be covered later) generate reports about the dependencies among the software components.

Examples:

2 Project Websites

2.1 Case study: Constructing a project website with Gradle

Let’s look at the process of building a simple website that provides

  1. A brief project description
  2. Links to (and copies of)

We can consider adding other content in later lessons.

2.1.1 Build plan

After a build, we can construct a website in build/reports by

  1. Copying build/doc/ into build/website

    • This gets a copy of the Javadocs

    • Note that the JUnit and project configuration reports will already be in subdirectories of build/reports.

  2. Copying HTML, CSS, and Javascript files from src/main/html into reports.

    • Hand-crafted pages with the project description and links to the three reports.

2.1.2 The HTML File

home_html.listing
<!DOCTYPE html>
<html>
	<head>
	    <title>Project Reports</title>
	    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
	    <link rel="stylesheet" type="text/css" href="projectReports.css"/>
	    <script src="projectReports.js"></script>
	</head>
	<body>
	    <h1>CodeCompCommon</h1>

        <p>This project provides a common set of interfaces for all CS350
           CodeComp project variants.</p>

        <p>It also provides a SharedPhrases class used to store token lists
           obtained via lexical analysis of the source code.</p>

        <h2>Information</h2>
		
        <p>Current version: 1.3</p>
        
	    <h2>Detailed Reports</h2>
		
	    <div class="reportLinks">
	   		<ul>
	   		    <li>General:
	   		        <ul>
	   			       <li><a href="../docs/javadoc/">JavaDoc</a></li>
	   			       <li><a href="../project/dependencies/root.html">Project Dependencies</a></li>
	   			    </ul></li>
	   			<li>Tests:
	   			    <ul>
	   			        <li><a href="../tests/test/">JUnit tests</a></li>
                    </ul>					
				</li>	    			
	   		</ul>
	   	</div>
	    
	</body>
</html>

2.1.3 Gradle setup

After a build, we can construct a website in build/reports by

  1. Copying build/doc/ into build/website
  2. Copying HTML, CSS, and Javascript files from src/main/html into reports.

    test.ignoreFailures=true ➀ check.dependsOn htmlDependencyReport ➁

    task copyWebPages (type: Copy) { ➄ from ‘src/main/html’ into ‘build/reports’ }

    task copyDocs (type: Copy) { ➃ from ‘build/docs’ into ‘build/reports/docs’ dependsOn ‘javadoc’ }

    task buildSite (dependsOn: [‘javadoc’, ‘check’, ➂ ‘copyWebPages’, ‘copyDocs’]) { description ‘Generate reports website for this project’ }

2.2 Case study: Constructing a project website with Gradle and Jbake

For a more elaborate, multi-page site, we can use a website generator to make it easy to enforce a common look-and-feel across pages.

Jbake injects content uses a series of templates

2.2.1 Gradle & Jbake

Gradle has a jbake plugin that add a bake task to generate a website.

2.2.2 The website setup

src
├── jbake
│   ├── assets
│   │   ├── css
│   │   │   └── base.css
│   │   └── js
│   │       └── jquery-1.11.1.min.js
│   ├── content
│   │   ├── dependencies.html
│   │   ├── home0.md
│   │   ├── javadoc.html
│   │   └── junit.html
│   ├── jbake.properties
│   └── templates
│       ├── footer.ftl
│       ├── header.ftl
│       ├── index.ftl
│       ├── menu.ftl
│       ├── page.ftl
│       └── sitemap.ftl

Templates:

page.ftl.listing
<#include "header.ftl">

	<div class="page-header">
		<h1><#escape x as x?xml>${content.title}</#escape></h1>
	</div>
	<p><em>${content.date?string("dd MMMM yyyy")}</em></p>
	<div class="center">
	    <#include "menu.ftl">
		<div class="rightpart">
			<p>${content.body}</p>
		</div>
	</div>
	<hr />

<#include "footer.ftl">
header.ftl.listing
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <title><#if (content.title)??><#escape x as x?xml>${content.title}</#escape><#else>codecentric</#if></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">
    <meta name="keywords" content="">
    <meta name="generator" content="JBake">

    <link href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>css/base.css" rel="stylesheet">

    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
    <!--[if lt IE 9]>
      <script src="<#if (content.rootpath)??>${content.rootpath}<#else></#if>js/html5shiv.min.js"></script>
    <![endif]-->

    <link rel="shortcut icon" href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>favicon.ico">
  </head>
  <body>
    <div id="mainBody">
   
menu.ftl.listing
<div class="leftPart">
  <div class="menuBlock">
    <span class="menuBlockHeader"><a href="<#if
										   (content.rootpath)??>${content.rootpath}<#else></#if>home.html">Home</a></span>
  </div>
  <div class="menuBlock">
    <span class="menuBlockHeader">Project Info</span>
	<ul>
      <li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>javadoc.html">API (Javadoc)</a></li>
      <li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>dependencies.html">Dependencies</a></li>
	</ul>
  </div>
  <div class="menuBlock">
    <span class="menuBlockHeader">Testing</span>
	<ul>
      <li><a href="<#if
      (content.rootpath)??>${content.rootpath}<#else></#if>junit.html">Unit
		  Tests</a></li>
	  <!--
      <li><a href="<#if
		(content.rootpath)??>${content.rootpath}<#else></#if>jacoco.html">Coverage</a></li>
-->
	</ul>
  </div>
  <!--
  <div class="menuBlock">
 	<span class="menuBlockHeader">Analysis Reports</span>
	<ul>
      <li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>checkstyle.html">Checkstyle</a></li>
      <li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>dependencies.html">Dependencies</a></li>
	</ul>
  </div>
-->
</div>
footer.ftl.listing
    </div>
    
    <div id="footer">
      <div class="container">
        <p class="muted credit">&copy; 2019 Old Dominion University</p>
      </div>
    </div>
    
    <script src="<#if (content.rootpath)??>${content.rootpath}<#else></#if>js/jquery-1.11.1.min.js"></script>
    
  </body>
</html>

Content:

junit.html.listing
title=CodeCompCommon Unit Tests
type=page
status=published
~~~~~~
</p>
<iframe class="docFrame" src="tests/test/index.html"/>
<p>
home0.md.listing
title=Project Documentation: CodeCompCommon
date=2019-03-18
type=page
status=published
~~~~~~

2.2.3 Build Steps

To generate a website in build/jbake

  1. Copy the build/reports and build/docs to build/tmp/website
  2. Copy src/jbake to build/tmp/website
  3. Concatenate build/tmp/website/content/home0.md and the project README.md to form build/tmp/website/content/home.md
  4. Run Jbake on build/tmp/website/content/home.md to generate the full website in build/jbake

In build.gradle:

build.gradle.jbake.listing
test.ignoreFailures=true
check.dependsOn htmlDependencyReport

task reports (dependsOn: ['javadoc', 'check']) {
    description 'Generate all reports for this project'
}


task copyJDocs (type: Copy) {
    from 'build/docs'
    into 'build/tmp/website/assets'
    dependsOn 'javadoc'
}

task copyReports (type: Copy) {
    from 'build/reports'
    into 'build/tmp/website/assets'
    dependsOn 'reports'
}

task copyJbakeTemplates (type: Copy) {
    from 'src/jbake'
    into 'build/tmp/website'
}

task buildHomePage (dependsOn: copyJbakeTemplates) {
	 inputs.files ( 'build/tmp/website/content/home0.md', '../README.md')
	 outputs.file ( 'build/tmp/website/content/home.md' )
	 doLast  {
	     outputs.files.singleFile.withOutputStream { out ->
	         for ( file in inputs.files ) file.withInputStream {
		 	     out << it << '\n' }
	    }
	 }
}

jbake {
	 srcDirName = "build/tmp/website"
}

task setupWebsite (dependsOn: ['buildHomePage', 'copyReports', 'copyJDocs']){
}

bake.dependsOn "setupWebsite"

2.3 Publishing to a website

The case studies above will build a website, but we still need to upload that to a web server.

2.3.1 Gradle: ssh solution

Gradle plugin org.hidetake:gradle-ssh-plugin allows you to

A plausible set of Gradle steps:

  1. Create a .zip file of the entire constructed website
  2. Use scp to upload the zip file to the remote server.
  3. Use ssh to issue an unzip command on the remote server.
  4. If necessary, use ssh to issue chmod commands as necessary on the unzipped content.

2.3.2 In build.gradle

plugins {
  id 'org.hidetake.ssh' version '2.9.0'
}

task zipWebsite (type: Zip, dependsOn: 'bake') {   ➀
    archiveFileName = 'website.zip'
    destinationDirectory = file('build')
    from 'build/jbake'
}

remotes {
  webServer {
    host = IP address
    user = userName
    identity = file(ssh-private-key)  ➁
  }
}

task deploy (dependsOn: 'zipWebsite') {
  doLast {
    ssh.run {
      session(remotes.webServer) {
       put from: 'build/website.zip', into: 'websitePath' ➂
       execute 'unzip websitePath/website.zip' -d websitePath➃
      }
    }
  }
}

2.3.3 There may be an easier way

I think it is much easier to handle this step in a continuous integration script, which we will study later.

2.4 Forges

A software forge is a collection of web services for the support of collaborative software devlopment:


Forge Examples

Among the best known forges are