Behind the scenes of the new Groovy website and documentation

Behind the scenes of the new Groovy website and documentation

The new Groovy website is the perfect example of the ""eating your own dogfood"" mantra. In this talk, we will explain the technologies used to build the new Groovy website, including Gradle, the Groovy MarkupTemplateEngine, Asciidoctor and automation of publication through TeamCity. You will learn how we put all those pieces together to create a toolchain that allows us to release new versions of Groovy will a fully tested documentation, as well as the generation of a static website only using Groovy technologies!

137d3908243acfc30e126615d59d4e6d?s=128

Guillaume Laforge

December 11, 2014
Tweet

Transcript

  1. Guillaume Laforge 
 @glaforge Behind the new Groovy website

  2. Guillaume Laforge Groovy project lead @glaforge http://glaforge.appspot.com

  3. Cédric Champeau Groovy core developer @cedricchampeau http://melix.github.io/blog/

  4. Cédric Champeau Groovy core developer @cedricchampeau http://melix.github.io/blog/

  5. Documentation

  6. Before

  7. None
  8. None
  9. After

  10. After

  11. After

  12. After

  13. After

  14. @glaforge New documentation goals • One documentation version per release

    • Integrated in the build process • Should be easy to write • Should be tested 10
  15. Executable documentation

  16. @glaforge How? Asciidoctor to the rescue! • Markup based documentation

    engine • Derived from Asciidoc • Lightweight syntax • Feature rich • Highly customizable 12
  17. @glaforge How? Asciidoctor to the rescue! 13 = Syntax
 


    This chapter covers the syntax of the Groovy programming language.
 The grammar of the language derives from the Java grammar,
 but enhances it with specific constructs for Groovy, and allows certain simplifications.
 
 == Comments
 
 === Single line comment
 
 Single line comments start with `//` and can be found at any position in the line.
 The characters following `//`, till the end of the line, are considered part of the comment.
  18. @glaforge Directory structure 14 src/spec/ assets doc test test-resources

  19. @glaforge Directory structure 14 src/spec/ assets doc test test-resources images,

    css, javascript…
  20. @glaforge Directory structure 14 src/spec/ assets doc test test-resources images,

    css, javascript… asciidoctor source files
  21. @glaforge Directory structure 14 src/spec/ assets doc test test-resources images,

    css, javascript… asciidoctor source files documentation specific tests
  22. @glaforge Directory structure 14 src/spec/ assets doc test test-resources images,

    css, javascript… asciidoctor source files documentation specific tests test sources
  23. Every single snippet of code you see in the documentation

    is tested
  24. OMG! Executable documentation!

  25. @glaforge Including external snippets of code 17 [source,groovy]
 ----
 include::src/spec/test/SyntaxTest.groovy[tags=single_line_comment,indent=0]


    ----
  26. @glaforge Including external snippets of code 17 [source,groovy]
 ----
 include::src/spec/test/SyntaxTest.groovy[tags=single_line_comment,indent=0]


    ---- Groovy syntax highlighting for the block of code
  27. @glaforge Including external snippets of code 17 [source,groovy]
 ----
 include::src/spec/test/SyntaxTest.groovy[tags=single_line_comment,indent=0]


    ---- Groovy syntax highlighting for the block of code include directive
  28. @glaforge Including external snippets of code 17 [source,groovy]
 ----
 include::src/spec/test/SyntaxTest.groovy[tags=single_line_comment,indent=0]


    ---- Groovy syntax highlighting for the block of code include directive source file to include
  29. @glaforge Including external snippets of code 17 [source,groovy]
 ----
 include::src/spec/test/SyntaxTest.groovy[tags=single_line_comment,indent=0]


    ---- Groovy syntax highlighting for the block of code include directive source file to include just include a portion
  30. @glaforge Snippet demarcation 18 void testSingleLineComment() {
 // tag::single_line_comment[]
 //

    a standalone single line comment
 println "hello" // a comment till the end of the line
 // end::single_line_comment[]
 }
  31. @glaforge Snippet demarcation 18 void testSingleLineComment() {
 // tag::single_line_comment[]
 //

    a standalone single line comment
 println "hello" // a comment till the end of the line
 // end::single_line_comment[]
 } tag::tag_name[] end::tag_name[]
  32. @glaforge Narrative 19 They can be seen as *interfaces* carrying

    both *default implementations* and *state*. A trait is defined using the `trait` keyword:
 
 [source,groovy]
 ----
 include::src/spec/test/TraitsSpecTest.groovy[tags=flying_simple,indent=0]
 ----
 <1> declaration of a trait
 <2> declaration of a method inside a trait
  33. @glaforge Callouts 20 class TraitsSpecTest extends GroovyTestCase {
 void testTraitDeclaration()

    {
 assertScript ''' // tag::flying_simple[]
 trait FlyingAbility { // <1>
 String fly() { "I'm flying!" } // <2>
 }
 // end::flying_simple[]
 
 // tag::bird[]
 class Bird implements FlyingAbility {} // <1>
 def b = new Bird() // <2>
 assert b.fly() == "I'm flying!" // <3>
 // end::bird[]
 '''
 }
  34. @glaforge Narrative and callouts rendered 21

  35. @glaforge Gradle 22 apply plugin: 'org.asciidoctor.gradle.asciidoctor'
 
 asciidoctor {
 def

    (full, major, minor, patch, flavor) = (groovyVersion =~ /(\d+)\.(\d++)\.(\d+)(?:-(.+))?/)[0]
 logDocuments = true
 sourceDir = project.file('src/spec/doc')
 options = [
 attributes: [
 'rootProjectDir': rootProject.projectDir,
 'source-highlighter': 'prettify',
 groovyversion: groovyVersion,
 'groovy-major-version': major,
 'groovy-minor-version': minor,
 'groovy-patch-version': patch,
 'groovy-full-version': groovyVersion,
 'groovy-short-version': "${major}.${minor}",
 doctype: 'book',
 revnumber: groovyVersion,
 icons: 'font',
 toc2: '',
 specfolder: 'src/spec/doc',
 linkcss: '',
 stylesheet: "assets/css/style.css",
 encoding: 'utf-8',
 toclevels: 10,
 numbered: ''
 ]
 ]
 }
  36. @glaforge In summary • Documentation rewritten from scratch – help

    still needed to fill the many gaps though! • Narrative written using Asciidoctor • Code must belong to test cases • Makes guarantees that doc is up-to-date • Integrated through Gradle 23
  37. Website

  38. After…

  39. After…

  40. After…

  41. After…

  42. After…

  43. @glaforge Objectives • Facelifting and responsiveness • Easy maintenance /

    hosting • Well organized • Make contributions easy • Eat your own dog food 26
  44. @glaforge Responsiveness 27

  45. @glaforge Responsiveness 27 Drop-down menu

  46. @glaforge Responsiveness 27 Drop-down menu Readable from any modern browsers,

    both desktop and mobile
  47. @glaforge Responsiveness 27 Drop-down menu Lead to Github’s online editor!

    Readable from any modern browsers, both desktop and mobile
  48. @glaforge Technical solution • Bootstrap theme by Damien Vitrac •

    Fully static • Uses a Groovy DSL for contents • Forkable on GitHub • Uses the Markup Template Engine • Baked with Gradle 28
  49. @glaforge Markup template engine • Introduced in Groovy 2.3 •

    Fully fledged template engine • Primarily aimed at generating markup contents • Templates look like Groovy builders • Statically compiled templates • Optional type checking 29
  50. @glaforge Markup template engine • No more closing tag nightmare

    • Can be very fast once templates are compiled • Support for i18n • Used in both Spring Boot and Ratpack 30
  51. @glaforge A basic template 31 downloads.each { dl -> div(class:'download')

    {
 a(href:dl.url, "Groovy $dl.version") }
 }
  52. @glaforge Template rendered 32 <div class="download">
 <a href="groovy238.html">Groovy 2.3.8</a>
 </div>


    <div class="download">
 <a href="groovy239.html">Groovy 2.3.9</a>
 </div>
  53. @glaforge Includes 33 include template: 'other_template.tpl'
 include unescaped: 'raw.txt'
 include

    escaped: 'to_be_escaped.txt'
  54. @glaforge Layouts 34 layout 'layouts/main.groovy', true,
 pageTitle: 'The Groovy programming

    language',
 mainContent: contents {
 div(id: 'content') {
 include unescaped: 'html/index.html'
 
 section(class: "row colset-3-article") {
 h1 { strong "Groovy events you shouldn't miss!" }
 allEvents.keySet().take(3).each { String eventName ->
 Event event = allEvents[eventName]
 article {
 div(class: 'content') {
 …
  55. @glaforge Layout 35 layout 'layouts/page.groovy', true,
 mainContent: contents {
 //

    'Content'
 div {
 include template: 'includes/topmenu.groovy'
 
 // main contents goes here!
 mainContent() 
 include template: 'includes/bottommenu.groovy'
 }
 }
  56. Starting the engine

  57. @glaforge Setting up the engine 37 def tplConf = new

    TemplateConfiguration( autoIndent : true, autoNewLine: true ) 
 def classLoader = … 
 tplEngine = new MarkupTemplateEngine(
 classLoader, tplConf,
 new CachingTemplateResolver())
  58. @glaforge Template resolver • Allows… – custom template resolution/loading –

    overriding i18n behavior – custom caching strategies 38
  59. @glaforge Rendering 39 tplEngine.createTemplateByPath("pages/${page}.groovy")
 .make(model)

  60. @glaforge Markup template engine • Even if a template contains

    unresolved variables – Statically compiled – Uses type checking extensions under the hood – Allows optional type checking of model – Even faster if type checked 40
  61. @glaforge Type checked models 41 modelTypes = { List<Page> pages

    } 
 pages.each { page -> p("Page title: $page.title") p(page.text)
 }
  62. @glaforge A DSL for the model • Templates generate contents

    • The model describes the website • Our model is described using a Groovy DSL 42
  63. @glaforge Sitemap.groovy 43 menu {
 group('Groovy') {
 item ‘Learn', 'learn.html'


    item 'Documentation', 'documentation.html'
 item 'Download', 'download.html'
 item 'Community', 'community.html'
 item 'Ecosystem', 'ecosystem.html'
 }
 
 group('About') {
 item 'Contributing', 'contribute.html'
 item 'Source code', 'https://github.com/groovy/groovy-core'
 item 'Build status', 'buildstatus.html'
 item 'Books', 'learn.html#books'
 item 'Sponsors', 'sponsors.html'
 item 'FAQ', 'faq.html'
 item 'Search', 'search.html'
 } …
  64. @glaforge Sitemap.groovy 44 ecosystem {
 project('Grails') {
 description '''Grails is

    an Open Source, full stack, web application framework for the JVM. It takes advantage of the Groovy programming language and convention over configuration to provide a productive and stream-lined development experience.'''
 url 'http://grails.org/'
 logo 'img/ecosystem/grails.png'
 }
 
 project('Gradle') {
 description '''Gradle is build automation evolved. Gradle can automate the building, testing, publishing, deployment and more of software packages or other types of projects such as generated static websites, generated documentation or indeed anything else.'''
 url 'http://gradle.org'
 logo 'img/ecosystem/gradle.gif'
 }
 …
  65. Baking…

  66. @glaforge Baking • sitemap.groovy contains the site “data” • MarkupTemplateEngine

    converts it to pages • Gradle – Compiles the generator – Generates the website – Checks for dead links in generated contents 46
  67. @glaforge Deployment • Gradle generates a static website • Can

    be deployed anywhere • For continuous deployment, we use TeamCity 47
  68. @glaforge TeamCity at Groovy • CI Server for Groovy •

    Tests, builds and releases Groovy • Build plans for JDK 5, 6, 7, 8 and even 9 • Tests every pull request before merge • We test early releases of the JDK (EA and sources) • http://ci.groovy-lang.org?guest=1 48
  69. None
  70. @glaforge TeamCity at Groovy • Server is sponsored by •

    Deployment of Groovy is done through • Releasing Groovy is: – Done through Artifactory plugin – One form + one click 50
  71. @glaforge Website deployment A commit on the master branch of

    website… • Triggers a build • Which generates a static website • Copied to the server if the build is successful 51
  72. @glaforge A word on GVM When a release is done:

    • GVM is notified • Download is made available in GVM • Done through a REST API • API Called directly from TeamCity • Thanks to... a Groovy script! 52
  73. @glaforge Groovy build-step in TeamCity • Groovy Build Step plugin

    – Allows you to write a build step as a Groovy script – Can be used to deploy, copy resources, web hooks ... 53
  74. Summary

  75. Executable documentation

  76. New website

  77. Simplified deployment

  78. Thanks for your attention!

  79. Q & A

  80. @glaforge Picture credits London: http://www.100percentoptical.com/images/2014/10/london.jpg Vomit:; http://youoffendmeyouoffendmyfamily.com/wordpress/wp-content/uploads/2011/09/vomit1.jpg Dinos: http://vergapipe.com/wp-content/uploads/2014/11/dinosaurs_wallpapers_free_download.jpg Future:

    http://www.hdwallsource.com/stunning-future-wallpaper-29256.html/stunning-future-wallpaper-29256 Gears: http://gearsoffate.com/wp-content/uploads/2014/09/Gears2.jpg Surprise: http://www.mentalactif.com/wp-content/uploads/2013/03/SURPRISE.jpg Plane: http://i.imgur.com/esCemkx.jpg Baking: http://www.nlinnovators.nl/wp-content/blogs.dir/1/files_mf/1409922073Navy_baking_bread.jpg 60