Project Reports & Websites

Steven J Zeil

Last modified: Dec 18, 2019

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:

<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-${}.paths</echo>
  <include file="build-${}.paths"/>

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

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

  <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"/>

  <target name="test" depends="compile-tests">
  	<property name="mypath" refid="testExecutionPath"/>
  	<echo>testExecutioPath is ${mypath}</echo>
    <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"/>
    <junitreport todir="target/test-results">
      <fileset dir="target/test-results/details">
        <include name="TEST-*.xml"/>
      <report format="frames" todir="target/test-results/html"/>

  <target name="build"  depends="test">
  	<jar destfile="codeAnnotation.jar" basedir="target/classes">
  		    <attribute name="Main-Class"

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


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 generate reports about the dependencies among the software components.


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

<!DOCTYPE html>
	    <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>

        <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>

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

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 adds a bake task to generate a website.

2.2.2 The website setup

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

The content directory` holds the actual information we want to disseminate.

The templates directory determines the “look and feel” of the website.


<#include "header.ftl">

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

<#include "footer.ftl">
<!DOCTYPE html>
<html lang="en">
    <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>

    <link rel="shortcut icon" href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>favicon.ico">
    <div id="mainBody">
<div class="leftPart">
  <div class="menuBlock">
    <span class="menuBlockHeader"><a href="<#if
  <div class="menuBlock">
    <span class="menuBlockHeader">Project Info</span>
      <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>
  <div class="menuBlock">
    <span class="menuBlockHeader">Testing</span>
      <li><a href="<#if
      <li><a href="<#if
  <div class="menuBlock">
 	<span class="menuBlockHeader">Analysis Reports</span>
      <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>
    <div id="footer">
      <div class="container">
        <p class="muted credit">&copy; 2019 Old Dominion University</p>
    <script src="<#if (content.rootpath)??>${content.rootpath}<#else></#if>js/jquery-1.11.1.min.js"></script>


title=CodeCompCommon Unit Tests
<iframe class="docFrame" src="tests/test/index.html"/>
title=Project Documentation: CodeCompCommon

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/ and the project to form build/tmp/website/content/
  4. Run Jbake on build/tmp/website/content/ to generate the full website in build/jbake

In build.gradle:

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/', '../')
	 outputs.file ( 'build/tmp/website/content/' )
	 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.

In build.gradle

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

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

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

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

2.3.2 Gradle: rsync solution

This approach can be used with the rsync-based file drops set up in earlier labs & assignments.

The Java library rsync4j-all provides a Java interface to rsync:

In build.gradle

buildscript {

    dependencies {
        classpath "com.github.fracpete:rsync4j-all:3.1.2-15"

import com.github.fracpete.rsync4j.RSync;  ➀
import com.github.fracpete.processoutput4j.output.ConsoleOutputProcessOutput;

task deployWebsite (dependsOn: "bake") {
    doLast {
        def sourceDir = "build/jbake/";
        def destURL = "destination";  ➁
        RSync rsync = new RSync()
                .rsh("ssh -o IdentitiesOnly=yes");  ➂
        ConsoleOutputProcessOutput output
                = new ConsoleOutputProcessOutput();


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