SlideShare a Scribd company logo
Abusing text/template
Arnaud Porterie - @icecrime - dotGo 2015
How can I get visibility into
my open source projects?
Collect
Store
Draw
Profit?
Filter
Rename
Enrich
Transform
1 {
2 "url": "https://api.github.com/repos/docker/docker/pulls/16603",
3 "id": 46083503,
4 "html_url": "https://github.com/docker/docker/pull/16603",
5 "diff_url": "https://github.com/docker/docker/pull/16603.diff",
6 "patch_url": "https://github.com/docker/docker/pull/16603.patch",
7 "issue_url": "https://api.github.com/repos/docker/docker/issues/16603",
8 "number": 16603,
9 "state": "closed",
10 "locked": false,
11 "title": "Add @vdemeester to MAINTAINERS",
12 "user": {
13 "login": "icecrime",
14 "id": 1564054,
15 "avatar_url": "https://avatars.githubusercontent.com/u/1564054?v=3",
16 "gravatar_id": "",
17 "url": "https://api.github.com/users/icecrime",
18 "html_url": "https://github.com/icecrime",
19 "followers_url": "https://api.github.com/users/icecrime/followers",
20 "following_url": "https://api.github.com/users/icecrime/following{/other_user}",
21 "gists_url": "https://api.github.com/users/icecrime/gists{/gist_id}",
22 "starred_url": "https://api.github.com/users/icecrime/starred{/owner}{/repo}",
23 "subscriptions_url": "https://api.github.com/users/icecrime/subscriptions",
24 "organizations_url": "https://api.github.com/users/icecrime/orgs",
25 "repos_url": "https://api.github.com/users/icecrime/repos",
26 "events_url": "https://api.github.com/users/icecrime/events{/privacy}",
27 "received_events_url": "https://api.github.com/users/icecrime/received_events",
28 "type": "User",
29 "site_admin": false
30 },
31 "body": ":tada:",
32 "created_at": "2015-09-26T15:16:23Z",
33 "updated_at": "2015-09-27T21:02:55Z",
34 "closed_at": "2015-09-27T19:14:39Z",
35 "merged_at": "2015-09-27T19:14:39Z",
36 "merge_commit_sha": "7fae194c5b4c694dc45a385866207df6bea57e61",
~~ ...
320 }
1 {
2 "url": "https://api.github.com/repos/docker/docker/pulls/16603",
3 "id": 46083503,
4 "html_url": "https://github.com/docker/docker/pull/16603",
5 "diff_url": "https://github.com/docker/docker/pull/16603.diff",
6 "patch_url": "https://github.com/docker/docker/pull/16603.patch",
7 "issue_url": "https://api.github.com/repos/docker/docker/issues/16603",
8 "number": 16603,
9 "state": "closed",
10 "locked": false,
11 "title": "Add @vdemeester to MAINTAINERS",
12 "user": {
13 "login": "icecrime",
14 "id": 1564054,
15 "avatar_url": "https://avatars.githubusercontent.com/u/1564054?v=3",
16 "gravatar_id": "",
17 "url": "https://api.github.com/users/icecrime",
18 "html_url": "https://github.com/icecrime",
19 "followers_url": "https://api.github.com/users/icecrime/followers",
20 "following_url": "https://api.github.com/users/icecrime/following{/other_user}",
21 "gists_url": "https://api.github.com/users/icecrime/gists{/gist_id}",
22 "starred_url": "https://api.github.com/users/icecrime/starred{/owner}{/repo}",
23 "subscriptions_url": "https://api.github.com/users/icecrime/subscriptions",
24 "organizations_url": "https://api.github.com/users/icecrime/orgs",
25 "repos_url": "https://api.github.com/users/icecrime/repos",
26 "events_url": "https://api.github.com/users/icecrime/events{/privacy}",
27 "received_events_url": "https://api.github.com/users/icecrime/received_events",
28 "type": "User",
29 "site_admin": false
30 },
31 "body": ":tada:",
32 "created_at": "2015-09-26T15:16:23Z",
33 "updated_at": "2015-09-27T21:02:55Z",
34 "closed_at": "2015-09-27T19:14:39Z",
35 "merged_at": "2015-09-27T19:14:39Z",
36 "merge_commit_sha": "7fae194c5b4c694dc45a385866207df6bea57e61",
~~ ...
320 }
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
"Hello dotGo!"
package main
import (
"os"
"text/template"
)
type Foo struct {
Bar string
}
type Something struct {
Foo Foo
}
const text = "Hello {{ .Foo.Bar }}!"
func main() {
obj := Something{
Foo{
Bar: "dotGo",
},
}
t, _ := template.New("").Parse(text)
t.Execute(os.Stdout, obj)
}
What if we...
● Fork text/template
● Substitute fmt.Fprint for a return
● Use the template syntax as a DSL for data transformation
● Describe the model in a TOML configuration file
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
[transformations.pull_request]
author = "{{ user_data .user.login }}"
body = "{{ .body }}"
closed_at = "{{ .closed_at }}"
created_at = "{{ .created_at }}"
labels = "{{ range .labels }}{{ .name }}{{ end }}"
merged = "{{ .merged }}"
ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}"
number = "{{ .number }}"
state = "{{ .state }}"
title = "{{ .title }}"
[transformations.pull_request]
author = "{{ user_data .user.login }}"
body = "{{ .body }}"
closed_at = "{{ .closed_at }}"
created_at = "{{ .created_at }}"
labels = "{{ range .labels }}{{ .name }}{{ end }}"
merged = "{{ .merged }}"
ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}"
number = "{{ .number }}"
state = "{{ .state }}"
title = "{{ .title }}"
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
Simple mapping
[transformations.pull_request]
author = "{{ user_data .user.login }}"
body = "{{ .body }}"
closed_at = "{{ .closed_at }}"
created_at = "{{ .created_at }}"
labels = "{{ range .labels }}{{ .name }}{{ end }}"
merged = "{{ .merged }}"
ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}"
number = "{{ .number }}"
state = "{{ .state }}"
title = "{{ .title }}"
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
Tests
[transformations.pull_request]
author = "{{ user_data .user.login }}"
body = "{{ .body }}"
closed_at = "{{ .closed_at }}"
created_at = "{{ .created_at }}"
labels = "{{ range .labels }}{{ .name }}{{ end }}"
merged = "{{ .merged }}"
ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}"
number = "{{ .number }}"
state = "{{ .state }}"
title = "{{ .title }}"
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
Loops
[transformations.pull_request]
author = "{{ user_data .user.login }}"
body = "{{ .body }}"
closed_at = "{{ .closed_at }}"
created_at = "{{ .created_at }}"
labels = "{{ range .labels }}{{ .name }}{{ end }}"
merged = "{{ .merged }}"
ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}"
number = "{{ .number }}"
state = "{{ .state }}"
title = "{{ .title }}"
{
"author": {
"login": "icecrime",
"company": "Docker",
"is_maintainer": true
},
"body": ":tada:",
"closed_at": "2015-09-27T19:14:39Z",
"created_at": "2015-09-26T15:16:23Z",
"labels": ["status/4-merge"],
"merged": true,
"ms": "1.9.0",
"number": 16603,
"state": "closed",
"title": "Add @vdemeester...",
}
User defined functions
TOML
JSON
Abusing text/template for data transformation
Profit!
Thank you
Arnaud Porterie - @icecrime
/icecrime/vossibility-collector

More Related Content

What's hot (20)

DOCX
Binomial heap
Kalpana Vijayaraghavan
 
PDF
Go for the would be network programmer
Eleanor McHugh
 
PDF
How to stand on the shoulders of giants
Ian Barber
 
PDF
The Browser Environment - A Systems Programmer's Perspective
Eleanor McHugh
 
DOCX
Arp
Ebsil Sherly
 
PDF
Python postgre sql a wonderful wedding
Stéphane Wirtel
 
PDF
Distributed Data Structures
PDX Web & Design
 
DOCX
Assignment no39
Jay Patel
 
PPTX
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QAFest
 
PDF
Playing 44CON CTF for fun and profit
44CON
 
PDF
Implementing virtual machines in go & c 2018 redux
Eleanor McHugh
 
PPTX
Introduzione a C#
Lorenz Cuno Klopfenstein
 
PPTX
C++ Lambda and concurrency
명신 김
 
PDF
Mozilla とブラウザゲーム
Noritada Shimizu
 
PDF
C++ TUTORIAL 7
Farhan Ab Rahman
 
DOCX
part2
Cameron White
 
DOC
Study of aloha protocol using ns2 network java proram
Meenakshi Devi
 
PDF
Go vs C++ - CppRussia 2019 Piter BoF
Timur Safin
 
PPTX
Introducing to Asynchronous Programming
Александр Федоров
 
Binomial heap
Kalpana Vijayaraghavan
 
Go for the would be network programmer
Eleanor McHugh
 
How to stand on the shoulders of giants
Ian Barber
 
The Browser Environment - A Systems Programmer's Perspective
Eleanor McHugh
 
Python postgre sql a wonderful wedding
Stéphane Wirtel
 
Distributed Data Structures
PDX Web & Design
 
Assignment no39
Jay Patel
 
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QAFest
 
Playing 44CON CTF for fun and profit
44CON
 
Implementing virtual machines in go & c 2018 redux
Eleanor McHugh
 
Introduzione a C#
Lorenz Cuno Klopfenstein
 
C++ Lambda and concurrency
명신 김
 
Mozilla とブラウザゲーム
Noritada Shimizu
 
C++ TUTORIAL 7
Farhan Ab Rahman
 
Study of aloha protocol using ns2 network java proram
Meenakshi Devi
 
Go vs C++ - CppRussia 2019 Piter BoF
Timur Safin
 
Introducing to Asynchronous Programming
Александр Федоров
 

More from Arnaud Porterie (10)

PDF
Docker Barcelona Meetup - An Introduction to BuildKit
Arnaud Porterie
 
PDF
Building software: the lessons from open source
Arnaud Porterie
 
PDF
DockerCon US 2016 - Extending Docker With APIs, Drivers, and Plugins
Arnaud Porterie
 
PDF
DockerCon US 2016 - Scaling Open Source operations
Arnaud Porterie
 
PDF
The rise of Docker, and the future of computing
Arnaud Porterie
 
PDF
DockerCon EU 2015 - Windows Server Containers
Arnaud Porterie
 
PDF
DockerCon US 2015 - Engine Breakout Session
Arnaud Porterie
 
PDF
DockerCon EU 2015 - The Latest on Docker Engine
Arnaud Porterie
 
PDF
Arnaud Porterie - Using Machine & Docker to develop & build Docker
Arnaud Porterie
 
PDF
Arnaud Porterie - The Truth About C++
Arnaud Porterie
 
Docker Barcelona Meetup - An Introduction to BuildKit
Arnaud Porterie
 
Building software: the lessons from open source
Arnaud Porterie
 
DockerCon US 2016 - Extending Docker With APIs, Drivers, and Plugins
Arnaud Porterie
 
DockerCon US 2016 - Scaling Open Source operations
Arnaud Porterie
 
The rise of Docker, and the future of computing
Arnaud Porterie
 
DockerCon EU 2015 - Windows Server Containers
Arnaud Porterie
 
DockerCon US 2015 - Engine Breakout Session
Arnaud Porterie
 
DockerCon EU 2015 - The Latest on Docker Engine
Arnaud Porterie
 
Arnaud Porterie - Using Machine & Docker to develop & build Docker
Arnaud Porterie
 
Arnaud Porterie - The Truth About C++
Arnaud Porterie
 
Ad

Recently uploaded (20)

PPTX
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PDF
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
PDF
Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
PPTX
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
PDF
How do you fast track Agentic automation use cases discovery?
DianaGray10
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PPTX
Digital Circuits, important subject in CS
contactparinay1
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PPTX
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Staying Human in a Machine- Accelerated World
Catalin Jora
 
PPTX
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
PDF
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
How do you fast track Agentic automation use cases discovery?
DianaGray10
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Digital Circuits, important subject in CS
contactparinay1
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Staying Human in a Machine- Accelerated World
Catalin Jora
 
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
Ad

Abusing text/template for data transformation

  • 1. Abusing text/template Arnaud Porterie - @icecrime - dotGo 2015
  • 2. How can I get visibility into my open source projects?
  • 4. Filter Rename Enrich Transform 1 { 2 "url": "https://api.github.com/repos/docker/docker/pulls/16603", 3 "id": 46083503, 4 "html_url": "https://github.com/docker/docker/pull/16603", 5 "diff_url": "https://github.com/docker/docker/pull/16603.diff", 6 "patch_url": "https://github.com/docker/docker/pull/16603.patch", 7 "issue_url": "https://api.github.com/repos/docker/docker/issues/16603", 8 "number": 16603, 9 "state": "closed", 10 "locked": false, 11 "title": "Add @vdemeester to MAINTAINERS", 12 "user": { 13 "login": "icecrime", 14 "id": 1564054, 15 "avatar_url": "https://avatars.githubusercontent.com/u/1564054?v=3", 16 "gravatar_id": "", 17 "url": "https://api.github.com/users/icecrime", 18 "html_url": "https://github.com/icecrime", 19 "followers_url": "https://api.github.com/users/icecrime/followers", 20 "following_url": "https://api.github.com/users/icecrime/following{/other_user}", 21 "gists_url": "https://api.github.com/users/icecrime/gists{/gist_id}", 22 "starred_url": "https://api.github.com/users/icecrime/starred{/owner}{/repo}", 23 "subscriptions_url": "https://api.github.com/users/icecrime/subscriptions", 24 "organizations_url": "https://api.github.com/users/icecrime/orgs", 25 "repos_url": "https://api.github.com/users/icecrime/repos", 26 "events_url": "https://api.github.com/users/icecrime/events{/privacy}", 27 "received_events_url": "https://api.github.com/users/icecrime/received_events", 28 "type": "User", 29 "site_admin": false 30 }, 31 "body": ":tada:", 32 "created_at": "2015-09-26T15:16:23Z", 33 "updated_at": "2015-09-27T21:02:55Z", 34 "closed_at": "2015-09-27T19:14:39Z", 35 "merged_at": "2015-09-27T19:14:39Z", 36 "merge_commit_sha": "7fae194c5b4c694dc45a385866207df6bea57e61", ~~ ... 320 }
  • 5. 1 { 2 "url": "https://api.github.com/repos/docker/docker/pulls/16603", 3 "id": 46083503, 4 "html_url": "https://github.com/docker/docker/pull/16603", 5 "diff_url": "https://github.com/docker/docker/pull/16603.diff", 6 "patch_url": "https://github.com/docker/docker/pull/16603.patch", 7 "issue_url": "https://api.github.com/repos/docker/docker/issues/16603", 8 "number": 16603, 9 "state": "closed", 10 "locked": false, 11 "title": "Add @vdemeester to MAINTAINERS", 12 "user": { 13 "login": "icecrime", 14 "id": 1564054, 15 "avatar_url": "https://avatars.githubusercontent.com/u/1564054?v=3", 16 "gravatar_id": "", 17 "url": "https://api.github.com/users/icecrime", 18 "html_url": "https://github.com/icecrime", 19 "followers_url": "https://api.github.com/users/icecrime/followers", 20 "following_url": "https://api.github.com/users/icecrime/following{/other_user}", 21 "gists_url": "https://api.github.com/users/icecrime/gists{/gist_id}", 22 "starred_url": "https://api.github.com/users/icecrime/starred{/owner}{/repo}", 23 "subscriptions_url": "https://api.github.com/users/icecrime/subscriptions", 24 "organizations_url": "https://api.github.com/users/icecrime/orgs", 25 "repos_url": "https://api.github.com/users/icecrime/repos", 26 "events_url": "https://api.github.com/users/icecrime/events{/privacy}", 27 "received_events_url": "https://api.github.com/users/icecrime/received_events", 28 "type": "User", 29 "site_admin": false 30 }, 31 "body": ":tada:", 32 "created_at": "2015-09-26T15:16:23Z", 33 "updated_at": "2015-09-27T21:02:55Z", 34 "closed_at": "2015-09-27T19:14:39Z", 35 "merged_at": "2015-09-27T19:14:39Z", 36 "merge_commit_sha": "7fae194c5b4c694dc45a385866207df6bea57e61", ~~ ... 320 } { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", }
  • 6. "Hello dotGo!" package main import ( "os" "text/template" ) type Foo struct { Bar string } type Something struct { Foo Foo } const text = "Hello {{ .Foo.Bar }}!" func main() { obj := Something{ Foo{ Bar: "dotGo", }, } t, _ := template.New("").Parse(text) t.Execute(os.Stdout, obj) }
  • 7. What if we... ● Fork text/template ● Substitute fmt.Fprint for a return ● Use the template syntax as a DSL for data transformation ● Describe the model in a TOML configuration file
  • 8. { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", } [transformations.pull_request] author = "{{ user_data .user.login }}" body = "{{ .body }}" closed_at = "{{ .closed_at }}" created_at = "{{ .created_at }}" labels = "{{ range .labels }}{{ .name }}{{ end }}" merged = "{{ .merged }}" ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}" number = "{{ .number }}" state = "{{ .state }}" title = "{{ .title }}"
  • 9. [transformations.pull_request] author = "{{ user_data .user.login }}" body = "{{ .body }}" closed_at = "{{ .closed_at }}" created_at = "{{ .created_at }}" labels = "{{ range .labels }}{{ .name }}{{ end }}" merged = "{{ .merged }}" ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}" number = "{{ .number }}" state = "{{ .state }}" title = "{{ .title }}" { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", } Simple mapping
  • 10. [transformations.pull_request] author = "{{ user_data .user.login }}" body = "{{ .body }}" closed_at = "{{ .closed_at }}" created_at = "{{ .created_at }}" labels = "{{ range .labels }}{{ .name }}{{ end }}" merged = "{{ .merged }}" ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}" number = "{{ .number }}" state = "{{ .state }}" title = "{{ .title }}" { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", } Tests
  • 11. [transformations.pull_request] author = "{{ user_data .user.login }}" body = "{{ .body }}" closed_at = "{{ .closed_at }}" created_at = "{{ .created_at }}" labels = "{{ range .labels }}{{ .name }}{{ end }}" merged = "{{ .merged }}" ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}" number = "{{ .number }}" state = "{{ .state }}" title = "{{ .title }}" { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", } Loops
  • 12. [transformations.pull_request] author = "{{ user_data .user.login }}" body = "{{ .body }}" closed_at = "{{ .closed_at }}" created_at = "{{ .created_at }}" labels = "{{ range .labels }}{{ .name }}{{ end }}" merged = "{{ .merged }}" ms = "{{ if $m := .milestone }}{{ $m.title }}{{ end }}" number = "{{ .number }}" state = "{{ .state }}" title = "{{ .title }}" { "author": { "login": "icecrime", "company": "Docker", "is_maintainer": true }, "body": ":tada:", "closed_at": "2015-09-27T19:14:39Z", "created_at": "2015-09-26T15:16:23Z", "labels": ["status/4-merge"], "merged": true, "ms": "1.9.0", "number": 16603, "state": "closed", "title": "Add @vdemeester...", } User defined functions
  • 15. Profit! Thank you Arnaud Porterie - @icecrime /icecrime/vossibility-collector