Skip to content

Commit 1d656e9

Browse files
committed
Initial commit
0 parents  commit 1d656e9

File tree

8 files changed

+173
-0
lines changed

8 files changed

+173
-0
lines changed

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Buildkite
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# JUnit Annotate Buildkite Plugin
2+
3+
A [Buildkite](https://buildkite.com/) plugin for annotating your builds with the test failures.
4+
5+
## Example
6+
7+
The following pipeline will run 50 `test.sh` jobs in parallel, and then process all the resulting JUnit XML files to create a summary build annotation.
8+
9+
```yml
10+
steps:
11+
- command: test.sh
12+
parallelism: 50
13+
artifact_paths: tmp/junit-*.xml
14+
- wait: ~
15+
continue_on_failure: true
16+
- plugins:
17+
junit-annotate#v0.0.1:
18+
artifacts: tmp/junit-*.xml
19+
```
20+
21+
## Configuration
22+
23+
### `artifacts` (required)
24+
25+
The artifact glob path to find the JUnit XML files.
26+
27+
Example: `tmp/junit-*.xml`
28+
29+
## License
30+
31+
MIT (see [LICENSE](LICENSE))

docker-compose.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: '2'
2+
services:
3+
tests:
4+
image: buildkite/plugin-tester
5+
volumes:
6+
- ".:/plugin"

hooks/command

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
junits_dir=$(mktemp -d -p "$(pwd)" "junits-tmp.XXXXXXXXXX")
6+
7+
function cleanup {
8+
rm -rf "${junits_dir}"
9+
}
10+
11+
trap cleanup EXIT
12+
13+
echo "--- :junit: Download the junits"
14+
15+
buildkite-agent artifact download "${BUILDKITE_PLUGIN_JUNIT_ANNOTATE_ARTIFACTS}" junits_dir
16+
17+
echo "--- :junit: Processing the junits"
18+
19+
docker run \
20+
--rm \
21+
-v "$(pwd)/src:/usr/src/app" \
22+
-v "${junits_dir}:/junits" \
23+
ruby:2.4 /usr/src/app/run.sh > "${junits_dir}/annotation.md"
24+
25+
cat "${junits_dir}/annotation.md"
26+
27+
echo "--- :buildkite: Creating annotation"
28+
29+
buildkite-agent annotate --context junit --style error < "${junits_dir}/annotation.md"

plugin.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "junit-annotate",
3+
"description": "Annotates your build using JUnit XML reports",
4+
"author": "@buildkite",
5+
"public": true,
6+
"requirements": ["docker"]
7+
}

src/junit.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env ruby
2+
3+
# Reads a list of junit files and returns a nice annotation on STDOUT
4+
#
5+
# Usage: junit.rb junit-1.xml junit-2.xml junit-3.xml
6+
7+
require 'nokogiri'
8+
require 'tempfile'
9+
10+
class Failure < Struct.new(:name, :classname, :body, :job); end
11+
12+
rspec_files = ARGV
13+
all_failures = []
14+
15+
rspec_files.each do |file|
16+
STDERR.puts "--- :junit: Parsing #{file}"
17+
job = file[/rspec-(.*).xml$/, 1]
18+
xml = File.read(file)
19+
doc = Nokogiri::XML(xml)
20+
21+
doc.search('//testcase').each do |testcase|
22+
name = testcase['name']
23+
classname = testcase['classname']
24+
failures = testcase.search("failure")
25+
26+
if failures.any?
27+
failures.each do |failure|
28+
all_failures << Failure.new(name, classname, failure.text.chomp.strip, job)
29+
end
30+
end
31+
end
32+
end
33+
34+
STDERR.puts "--- ❓ Checking failures"
35+
36+
if all_failures.empty?
37+
STDERR.puts "No failures, all good!"
38+
exit 0
39+
else
40+
STDERR.puts "There are #{all_failures.length} errors... (boo)"
41+
end
42+
43+
STDERR.puts "--- ✍️ Preparing annotation"
44+
45+
buffer = "There were #{all_failures.length} failures:\n\n"
46+
all_failures.each do |failure|
47+
buffer << "<details>\n"
48+
buffer << "<summary><code>#{failure.name} in #{failure.classname}</code></summary>\n\n"
49+
buffer << "<code><pre>#{failure.body}</pre></code>\n\n"
50+
buffer << %{in <a href="##{failure.job}">Job ##{failure.job}</a>\n}
51+
buffer << "</details>"
52+
buffer << "\n\n\n"
53+
end
54+
55+
puts buffer
56+
57+
STDERR.puts "--- :buildkite: Creating annotation"
58+
59+
file = File.new("junit-annotation.md")
60+
file.write(buffer)
61+
file.close

src/run.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
gem install nokogiri --quiet --silent
6+
7+
ruby junit.rb /junits/*

tests/command.bats

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bats
2+
3+
load "$BATS_PATH/load.bash"
4+
5+
@test "calls git log" {
6+
stub git "log : echo some-log"
7+
git log
8+
assert_success
9+
unstub git
10+
}

0 commit comments

Comments
 (0)