├── .ruby-version ├── .github ├── release-drafter.yml └── workflows │ └── release-drafter.yml ├── Rakefile ├── .gitignore ├── bin ├── setup └── console ├── lib └── asciidoctor │ └── jenkins │ ├── extensions │ ├── version.rb │ ├── plugin-link.rb │ ├── author-link.rb │ ├── jep-link.rb │ ├── jira-link.rb │ ├── security-link.rb │ ├── pipeline-block.rb │ └── javadoc-link.rb │ └── extensions.rb ├── spec ├── spec_helper.rb ├── javadoc_spec.rb ├── staplerdoc_spec.rb ├── pipeline_spec.rb └── jenkinsdoc_spec.rb ├── examples ├── plugin.adoc ├── basic.adoc ├── author.adoc ├── jep.adoc ├── jira.adoc ├── pipeline.adoc ├── security.adoc └── javadoc.adoc ├── Gemfile ├── renovate.json ├── Jenkinsfile ├── asciidoctor-jenkins-extensions.gemspec ├── Gemfile.lock ├── config.ru └── README.adoc /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.8 2 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new 5 | 6 | task default: [:build] 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | *.sw* 10 | .idea 11 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/version.rb: -------------------------------------------------------------------------------- 1 | module Asciidoctor 2 | module Jenkins 3 | module Extensions 4 | VERSION = "0.9.0" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'rspec/its' 3 | 4 | $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib')) 5 | 6 | RSpec.configure do |c| 7 | c.color = true 8 | end 9 | -------------------------------------------------------------------------------- /examples/plugin.adoc: -------------------------------------------------------------------------------- 1 | = plugin macro 2 | 3 | The `plugin` inline macro can be used to link to plugins on the plugins index 4 | at https://plugins.jenkins.io/. 5 | 6 | Example: 7 | 8 | plugin:git[The Git Plugin] 9 | -------------------------------------------------------------------------------- /examples/basic.adoc: -------------------------------------------------------------------------------- 1 | = Basic Example 2 | 3 | This is simple a basic example of *Asciidoc* formatting. 4 | 5 | 6 | Consult the 7 | link:http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[quick 8 | reference] for more 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in asciidoctor-jenkins-extensions.gemspec 4 | gemspec 5 | 6 | 7 | group :acceptance_test do 8 | gem 'sinatra' 9 | gem 'shotgun' 10 | end 11 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions.rb: -------------------------------------------------------------------------------- 1 | module Asciidoctor 2 | module Jenkins 3 | module Extensions 4 | end 5 | end 6 | end 7 | 8 | Dir.glob("#{File.dirname(__FILE__)}/extensions/**/*.rb").each do |f| 9 | require f 10 | end 11 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "asciidoctor/jenkins/extensions" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":semanticCommitsDisabled" 6 | ], 7 | "regexManagers": [ 8 | { 9 | "fileMatch": ["Jenkinsfile"], 10 | "matchStrings": ["image 'ruby:(?.*?)'\n"], 11 | "depNameTemplate": "ruby", 12 | "datasourceTemplate": "docker" 13 | } 14 | ], 15 | "rebaseWhen": "conflicted" 16 | } 17 | -------------------------------------------------------------------------------- /examples/author.adoc: -------------------------------------------------------------------------------- 1 | = Author macro 2 | 3 | The `author` inline macro can be used to link to author's blog page. 4 | 5 | ### Example 1 6 | 7 | author:timja[Tim Jacomb] 8 | 9 | Source: 10 | 11 | ``` 12 | author:timja[Tim Jacomb] 13 | ``` 14 | 15 | Result: link:/blog/authors/timja[Tim Jacomb] 16 | 17 | ### Example 2 18 | 19 | author:timja[] 20 | 21 | Source: 22 | 23 | ``` 24 | author:timja[] 25 | ``` 26 | 27 | Result: link:/blog/authors/timja[timja] 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - main 8 | 9 | jobs: 10 | update_release_draft: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # Drafts your next Release notes as Pull Requests are merged into "master" 14 | - uses: release-drafter/release-drafter@v6 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | pipeline { 4 | agent { 5 | docker { 6 | image 'ruby:3.4.8' 7 | label 'docker&&linux' 8 | } 9 | } 10 | 11 | stages { 12 | stage('Build and Test') { 13 | steps { 14 | sh 'gem install bundler -N && bundle install' 15 | sh 'bundle exec rake' 16 | } 17 | } 18 | } 19 | 20 | post { 21 | always { 22 | archiveArtifacts('pkg/*.gem') 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/plugin-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # plugin:git[Git plugin] 7 | # 8 | Asciidoctor::Extensions.register do 9 | inline_macro do 10 | named :plugin 11 | name_positional_attributes 'label' 12 | 13 | process do |parent, target, attrs| 14 | label = attrs['label'] 15 | target = %(https://plugins.jenkins.io/#{target}) 16 | (create_anchor parent, label, type: :link, target: target).render 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/author-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # author:timja[Tim Jacomb] 7 | # author:timja[] 8 | # 9 | Asciidoctor::Extensions.register do 10 | inline_macro do 11 | named :author 12 | name_positional_attributes 'label' 13 | 14 | process do |parent, target, attrs| 15 | if attrs['label'] 16 | label = %(#{attrs['label']}) 17 | else 18 | label = %(#{target}) 19 | end 20 | target = %(/blog/authors/#{target}) 21 | (create_anchor parent, label, type: :link, target: target).render 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /examples/jep.adoc: -------------------------------------------------------------------------------- 1 | = jep macro 2 | 3 | The `jep` inline macro can be used to link to Jenkins Enhancement Proposals 4 | at https://github.com/jenkinsci/jep/tree/master/jep. 5 | 6 | ### Example 1 7 | 8 | jep:201[Jenkins Configuration as Code] 9 | 10 | Source: 11 | 12 | ``` 13 | jep:201[Jenkins Configuration as Code] 14 | ``` 15 | 16 | Result: link:https://github.com/jenkinsci/jep/blob/master/jep/201/README.adoc[JEP-201: Jenkins Configuration as Code] 17 | 18 | ### Example 2 19 | 20 | jep:201[] 21 | 22 | Source: 23 | 24 | ``` 25 | jep:201[] 26 | ``` 27 | 28 | Result: link:https://github.com/jenkinsci/jep/blob/master/jep/201/README.adoc[JEP-201] 29 | 30 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/jep-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # jep:201[Jenkins Configuration as Code] 7 | # 8 | Asciidoctor::Extensions.register do 9 | inline_macro do 10 | named :jep 11 | name_positional_attributes 'label' 12 | 13 | process do |parent, target, attrs| 14 | if attrs['label'] 15 | label = %(JEP-#{target}: #{attrs['label']}) 16 | else 17 | label = %(JEP-#{target}) 18 | end 19 | target = %(https://github.com/jenkinsci/jep/blob/master/jep/#{target}/README.adoc) 20 | (create_anchor parent, label, type: :link, target: target).render 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/jira-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # jira:JENKINS-12345[Issue description] 7 | # 8 | Asciidoctor::Extensions.register do 9 | inline_macro do 10 | named :jira 11 | name_positional_attributes 'label' 12 | 13 | process do |parent, target, attrs| 14 | if target.include? "-" 15 | issueId = target 16 | else 17 | issueId = %(JENKINS-#{target}) 18 | end 19 | 20 | if attrs['label'] 21 | label = %(#{issueId}: #{attrs['label']}) 22 | else 23 | label = issueId 24 | end 25 | 26 | target = %(https://issues.jenkins.io/browse/#{issueId}) 27 | (create_anchor parent, label, type: :link, target: target).render 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /examples/jira.adoc: -------------------------------------------------------------------------------- 1 | = jira macro 2 | 3 | The `jira` inline macro can be used to link to plugins on the plugins index 4 | at https://issues.jenkins.io/. 5 | 6 | ### Example 1. Referencing JENKINS project 7 | 8 | jira:38313[Jenkins Configuration as Code] 9 | 10 | Source: 11 | 12 | ``` 13 | jira:38313[Jenkins Configuration as Code] 14 | ``` 15 | 16 | Result: link:https://issues.jenkins.io/browse/JENKINS-38313[JENKINS-38313: External Build Log storage for Jenkins] 17 | 18 | ### Example 2. Referencing non-JENKINS projects 19 | 20 | jira:INFRA-1760[Create "jep" and "jira" macros for jenkins.io] 21 | 22 | Source: 23 | 24 | ``` 25 | jira:INFRA-1760[Create "jep" and "jira" macros for jenkins.io] 26 | ``` 27 | 28 | Result: link:https://issues.jenkins.io/browse/INFRA-1760[INFRA-1760: Create "jep" and "jira" macros for jenkins.io] 29 | 30 | ### Example 3. Reference without text 31 | 32 | jira:38313[] 33 | 34 | Source: 35 | 36 | ``` 37 | jira:38313[] 38 | ``` 39 | 40 | Result: link:https://issues.jenkins.io/browse/JENKINS-38313[JENKINS-38313] 41 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/security-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # security:12345[Issue description, date] 7 | # 8 | Asciidoctor::Extensions.register do 9 | inline_macro do 10 | named :security 11 | name_positional_attributes 'label', 'date' 12 | 13 | process do |parent, target, attrs| 14 | if target.include? "-" 15 | issueId = target 16 | else 17 | issueId = %(SECURITY-#{target}) 18 | end 19 | 20 | if attrs['label'] 21 | label = %(#{issueId}: #{attrs['label']}) 22 | else 23 | label = issueId 24 | end 25 | 26 | if attrs['date'] 27 | target = %(https://jenkins.io/security/advisory/#{attrs['date']}/##{issueId}) 28 | else 29 | # TODO(oleg_nenashev): Change to a security issue redirect service if it gets created 30 | target = %(https://jenkins.io/security/advisories/) 31 | end 32 | 33 | (create_anchor parent, label, type: :link, target: target).render 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /examples/pipeline.adoc: -------------------------------------------------------------------------------- 1 | = [pipeline] block examples 2 | 3 | 4 | This file contains some examples for using the `[pipeline]` block 5 | 6 | == Defining both Scripted and Declarative 7 | 8 | [pipeline] 9 | ---- 10 | // Script // 11 | node { 12 | stage('Build') { 13 | checkout scm 14 | // Install dependencies 15 | sh 'npm install' 16 | } 17 | } 18 | 19 | // Declarative // 20 | pipeline { 21 | agent docker: 'node:6.3' 22 | stages { 23 | stage('Build') { 24 | sh 'npm install' 25 | } 26 | } 27 | } 28 | ---- 29 | 30 | == Defining only one syntax 31 | 32 | === Scripted 33 | 34 | [pipeline] 35 | ---- 36 | // Script // 37 | node { 38 | stage('Build') { 39 | checkout scm 40 | // Install dependencies 41 | sh 'npm install' 42 | } 43 | } 44 | ---- 45 | 46 | === Declarative 47 | 48 | [pipeline] 49 | ---- 50 | // Declarative // 51 | pipeline { 52 | agent docker: 'node:6.3' 53 | stages { 54 | stage('Build') { 55 | sh 'npm install' 56 | } 57 | } 58 | } 59 | ---- 60 | -------------------------------------------------------------------------------- /examples/security.adoc: -------------------------------------------------------------------------------- 1 | = security macro 2 | 3 | The `security` inline macro can be used to reference security fixes 4 | in Jenkins Security advisories: https://jenkins.io/security/advisories/. 5 | 6 | ### Example 1. Referencing SECURITY issues 7 | 8 | The macro also allows referencing SECURITY issues. 9 | These issues are not public, so an advisory is linked instead. 10 | Currently it requires issueDate to be specified as a second macro argument. 11 | 12 | security:637["Jenkins allowed deserialization of URL objects with host components", "2018-08-15"] 13 | 14 | Source: 15 | 16 | ``` 17 | security:637["Jenkins allowed deserialization of URL objects with host components", "2018-08-15"] 18 | ``` 19 | 20 | Result: link:https://jenkins.io/security/advisory/2018-08-15/#SECURITY-637[SECURITY-637: Jenkins allowed deserialization of URL objects with host components] 21 | 22 | ### Example 2. Referencing SECURITY issues without text 23 | 24 | The macro also allows referencing 25 | 26 | security:1076[date="2018-08-15"] 27 | 28 | Source: 29 | 30 | ``` 31 | security:1076[date="2018-08-15"] 32 | ``` 33 | 34 | Result: link:https://jenkins.io/security/advisory/2018-08-15/#SECURITY-1076[SECURITY-1076] 35 | 36 | -------------------------------------------------------------------------------- /spec/javadoc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'asciidoctor' 4 | require 'asciidoctor/jenkins/extensions' 5 | 6 | describe 'the javadoc macro' do 7 | subject(:rendering) { Asciidoctor.render(document) } 8 | 9 | context 'with a simple document' do 10 | let(:document) { 11 | "javadoc:java.nio.file.DirectoryStream.Filter[]" 12 | } 13 | 14 | it 'should render properly' do 15 | expect(rendering).to match(/https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/nio\/file\/DirectoryStream.Filter.html.+>java.nio.file.DirectoryStream.Filter/) 16 | end 17 | end 18 | 19 | context 'with label' do 20 | let(:document) { 21 | "javadoc:java.io.File[file]" 22 | } 23 | 24 | it 'should render properly' do 25 | expect(rendering).to match(/https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/io\/File.html.+>file/) 26 | end 27 | end 28 | 29 | context 'with a fragment' do 30 | let(:document) { 31 | "javadoc:java.io.File#pathSeparator[]" 32 | } 33 | 34 | it 'should render properly' do 35 | expect(rendering).to match(/https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/io\/File.html#pathSeparator.+>java.io.File/) 36 | end 37 | end 38 | end -------------------------------------------------------------------------------- /asciidoctor-jenkins-extensions.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'asciidoctor/jenkins/extensions/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "asciidoctor-jenkins-extensions" 8 | spec.version = Asciidoctor::Jenkins::Extensions::VERSION 9 | spec.authors = ["R. Tyler Croy"] 10 | spec.email = ["tyler@monkeypox.org"] 11 | 12 | spec.summary = "a collection of Asciidoctor extensions which enable more advanced 13 | formatting in Jenkins-related content. 14 | " 15 | spec.description = "a collection of Asciidoctor extensions which enable more advanced 16 | formatting in Jenkins-related content. 17 | " 18 | spec.homepage = 'https://github.com/jenkins-infra/asciidoctor-jenkins-extensions' 19 | 20 | 21 | root = File.dirname(__FILE__) 22 | spec.files = Dir.glob("#{root}/lib/**/*.rb").map { |f| f.gsub("#{root}/", '') } 23 | spec.files << File.basename(__FILE__) 24 | spec.bindir = "exe" 25 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 26 | spec.require_paths = ["lib"] 27 | 28 | 29 | spec.add_dependency 'asciidoctor', '>= 2.0.18' 30 | spec.add_dependency 'coderay', '~> 1.1.3' 31 | spec.add_dependency 'colorize', '~> 0.8.1' 32 | 33 | spec.add_development_dependency "bundler", "~> 2.3.26" 34 | spec.add_development_dependency "rake", "~> 13.0.3" 35 | spec.add_development_dependency "rspec" 36 | spec.add_development_dependency "rspec-its" 37 | spec.add_development_dependency 'pry' 38 | end 39 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | asciidoctor-jenkins-extensions (0.9.0) 5 | asciidoctor (>= 2.0.18) 6 | coderay (~> 1.1.3) 7 | colorize (~> 0.8.1) 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | specs: 12 | asciidoctor (2.0.18) 13 | base64 (0.3.0) 14 | coderay (1.1.3) 15 | colorize (0.8.1) 16 | diff-lcs (1.5.0) 17 | logger (1.7.0) 18 | method_source (1.0.0) 19 | mustermann (3.0.4) 20 | ruby2_keywords (~> 0.0.1) 21 | pry (0.14.1) 22 | coderay (~> 1.1) 23 | method_source (~> 1.0) 24 | rack (3.2.3) 25 | rack-protection (4.2.1) 26 | base64 (>= 0.1.0) 27 | logger (>= 1.6.0) 28 | rack (>= 3.0.0, < 4) 29 | rack-session (2.1.1) 30 | base64 (>= 0.1.0) 31 | rack (>= 3.0.0) 32 | rake (13.0.6) 33 | rspec (3.12.0) 34 | rspec-core (~> 3.12.0) 35 | rspec-expectations (~> 3.12.0) 36 | rspec-mocks (~> 3.12.0) 37 | rspec-core (3.12.0) 38 | rspec-support (~> 3.12.0) 39 | rspec-expectations (3.12.1) 40 | diff-lcs (>= 1.2.0, < 2.0) 41 | rspec-support (~> 3.12.0) 42 | rspec-its (1.3.0) 43 | rspec-core (>= 3.0.0) 44 | rspec-expectations (>= 3.0.0) 45 | rspec-mocks (3.12.1) 46 | diff-lcs (>= 1.2.0, < 2.0) 47 | rspec-support (~> 3.12.0) 48 | rspec-support (3.12.0) 49 | ruby2_keywords (0.0.5) 50 | shotgun (0.9.2) 51 | rack (>= 1.0) 52 | sinatra (4.2.1) 53 | logger (>= 1.6.0) 54 | mustermann (~> 3.0) 55 | rack (>= 3.0.0, < 4) 56 | rack-protection (= 4.2.1) 57 | rack-session (>= 2.0.0, < 3) 58 | tilt (~> 2.0) 59 | tilt (2.6.1) 60 | 61 | PLATFORMS 62 | ruby 63 | 64 | DEPENDENCIES 65 | asciidoctor-jenkins-extensions! 66 | bundler (~> 2.3.26) 67 | pry 68 | rake (~> 13.0.3) 69 | rspec 70 | rspec-its 71 | shotgun 72 | sinatra 73 | 74 | BUNDLED WITH 75 | 2.3.26 76 | -------------------------------------------------------------------------------- /spec/staplerdoc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'asciidoctor' 4 | require 'asciidoctor/jenkins/extensions' 5 | 6 | describe 'the staplerdoc macro' do 7 | subject(:rendering) { Asciidoctor.render(document) } 8 | 9 | context 'with a simple document' do 10 | let(:document) { 11 | "staplerdoc:org.kohsuke.stapler.AncestorInPath[]" 12 | } 13 | 14 | it 'should render properly' do 15 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/stapler\/org\/kohsuke\/stapler\/AncestorInPath.html.+>org.kohsuke.stapler.AncestorInPath/) 16 | end 17 | end 18 | 19 | context 'with label' do 20 | let(:document) { 21 | "staplerdoc:org.kohsuke.stapler.AncestorInPath[a label]" 22 | } 23 | 24 | it 'should render properly' do 25 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/stapler\/org\/kohsuke\/stapler\/AncestorInPath.html.+>a label/) 26 | end 27 | end 28 | 29 | context 'with a fragment' do 30 | let(:document) { 31 | "staplerdoc:org.kohsuke.stapler.WebMethodContext#getName()[]" 32 | } 33 | 34 | it 'should render properly' do 35 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/stapler\/org\/kohsuke\/stapler\/WebMethodContext.html#getName--.+>org.kohsuke.stapler.WebMethodContext/) 36 | end 37 | end 38 | 39 | context 'with a complex fragment' do 40 | let(:document) { 41 | "staplerdoc:org.kohsuke.stapler.ReflectionUtils#union-java.lang.annotation.Annotation:A-java.lang.annotation.Annotation:A-[]" 42 | } 43 | 44 | it 'should render properly' do 45 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/stapler\/org\/kohsuke\/stapler\/ReflectionUtils.html#union-java.lang.annotation.Annotation:A-java.lang.annotation.Annotation:A-.+>org.kohsuke.stapler.ReflectionUtils/) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/pipeline_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'asciidoctor' 4 | require 'asciidoctor/jenkins/extensions' 5 | 6 | describe 'the pipeline block' do 7 | subject(:rendering) { Asciidoctor.render(document) } 8 | # This regex will indicate that the HTML rendering contains at least the 9 | # proper opening of our [pipeline] block 10 | let(:pipeline_div) { /
/ } 11 | 12 | context 'with a simple document' do 13 | let(:document) { 14 | "Hello *World*" 15 | } 16 | 17 | it 'should render properly' do 18 | expect(rendering).to match(/World<\/strong>/) 19 | end 20 | end 21 | 22 | context 'with a one-part [pipeline] block' do 23 | let(:document) { 24 | ''' 25 | [pipeline] 26 | ---- 27 | Invalid Pipeline block 28 | ---- 29 | ''' 30 | } 31 | 32 | it 'should warn to stderr' do 33 | expect($stderr).to receive(:puts).exactly(2).times 34 | expect(rendering).to match(pipeline_div) 35 | end 36 | end 37 | 38 | context 'with a Scripted [pipeline] block' do 39 | let(:document) { 40 | ''' 41 | [pipeline] 42 | ---- 43 | // Scripted // 44 | node { 45 | echo "hello world" 46 | } 47 | ---- 48 | ''' 49 | } 50 | 51 | it 'should warn about missing declarative to stderr' do 52 | expect($stderr).to receive(:puts).once 53 | expect(rendering).to match(pipeline_div) 54 | end 55 | end 56 | 57 | context 'with a [pipeline] block containing both syntaxes' do 58 | let(:document) { 59 | ''' 60 | [pipeline] 61 | ---- 62 | // Scripted // 63 | node { 64 | echo "hello world" 65 | } 66 | // Declarative // 67 | pipeline { 68 | agent any 69 | stages { stage("Hello") { steps { echo "World" } } } 70 | } 71 | ---- 72 | ''' 73 | } 74 | 75 | it 'should not warn and render a proper block' do 76 | expect($stderr).to receive(:puts).never 77 | expect(rendering).to match(pipeline_div) 78 | end 79 | 80 | it 'should contain a Declarative Pipeline' do 81 | expect(rendering).to match(/Jenkinsfile \(Declarative Pipeline\)/) 82 | end 83 | 84 | it 'should contain a Scripted Pipeline' do 85 | expect(rendering).to match(/Jenkinsfile \(Scripted Pipeline\)/) 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /examples/javadoc.adoc: -------------------------------------------------------------------------------- 1 | = javadoc macro examples 2 | 3 | 4 | Below are some examples of using the `jenkinsdoc`, `staplerdoc`, and `javadoc` 5 | macros. 6 | 7 | The `jenkinsdoc` inline macro can be used to link to the Jenkins Javadoc at https://javadoc.jenkins.io/. 8 | 9 | It supports a variety of different syntaxes. For classes in Jenkins core: 10 | 11 | * jenkinsdoc:hudson.scm.SCM[] links to the full URL for the class in Jenkins core. 12 | * jenkinsdoc:hudson.scm.SCM#all()[] links to the full URL for the class in Jenkins core, and includes a fragment. 13 | * jenkinsdoc:SCM[] links to the `/byShortName` URL for the class in Jenkins core. Due to the redirect, fragments won't work here. 14 | 15 | By default, all of these use the class name as label, but that can be customized if necessary by providing an alternative label between the square brackets. 16 | 17 | jenkinsdoc:hudson.scm.SCM#all()[a list of all known SCM implementations] 18 | 19 | The first class name component starting with an uppercase character is considered to start the class name. Everything before that component is considered to be part of the package name. 20 | 21 | * jenkinsdoc:jenkins.model.lazy.BuildReference.HolderFactory[] 22 | * jenkinsdoc:BuildReference.HolderFactory[] 23 | 24 | --- 25 | 26 | For classes in plugins, the plugin's name (`artifactId`) is put before the class name and separated by colon: 27 | 28 | * jenkinsdoc:git:hudson.plugins.git.GitSCM[] links to the full URL for the class in the git plugin. 29 | * jenkinsdoc:git:hudson.plugins.git.GitSCM#getRepositories--[] links to the full URL for the class in the git plugin, and includes a fragment. 30 | 31 | --- 32 | 33 | For classes in components, the component's (`artifactId`) is put before the class name and separated by colon, note the `component` selector is also required: 34 | 35 | * jenkinsdoc:component:remoting:hudson.remoting.Channel[] links to the full URL for the class in the remoting component. 36 | * jenkinsdoc:component:remoting:hudson.remoting.Channel#classLoadingCount[] links to the full URL for the class in the remoting component, and includes a fragment. 37 | 38 | --- 39 | 40 | Two other inline macros, `staplerdoc` and `javadoc` exist and link to the 41 | Stapler API documentation and Java API documentation, respectively. These do 42 | not support the form of `jenkinsci` that only requires the short name, but 43 | otherwise work the same way. 44 | 45 | Examples: 46 | 47 | * javadoc:java.io.File#pathSeparator[the path separator] 48 | * javadoc:java.nio.file.DirectoryStream.Filter[] 49 | * staplerdoc:org.kohsuke.stapler.AncestorInPath[] 50 | * staplerdoc:org.kohsuke.stapler.AncestorInPath.HandlerImpl[] -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'colorize' 4 | require 'sinatra' 5 | 6 | $LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib') 7 | require 'asciidoctor/jenkins/extensions' 8 | 9 | class ExtensionsTestApplication < Sinatra::Base 10 | set :views, 'examples' 11 | 12 | ASSETS = <<-EOF 13 | 14 | 15 | EOF 16 | 17 | # This template will be used by default for all the playground routes 18 | template :layout do 19 | <<-EOF 20 | 21 | 22 | Asciidoctor::Jenkins::Extensions Playground 23 | #{ASSETS} 24 | 25 | 26 |
27 |

<%= name %>.adoc

28 | 39 |
40 |
41 |
42 |
43 |
44 | <%= yield %> 45 |
46 |
<%= raw %>
47 |
48 |
49 | 50 | ' 51 | EOF 52 | end 53 | 54 | template :index do 55 | <<-EOF 56 | 57 | 58 | Asciidoctor::Jenkins::Extensions Playground 59 | #{ASSETS} 60 | 61 | 62 |
63 |

Asciidoctor::Jenkins::Extensions Playground

64 |
65 | Available documents 66 | 73 |
74 | 75 | 76 | EOF 77 | end 78 | 79 | examples = Dir.glob("#{File.dirname(__FILE__)}/examples/*.adoc") 80 | example_routes = examples.collect { |e| File.basename(e).split('.').first } 81 | puts "Found all examples: #{examples}" 82 | 83 | example_routes.each_index do |index| 84 | route = example_routes[index] 85 | get "/#{route}" do 86 | asciidoc route.to_sym, 87 | layout_engine: :erb, 88 | locals: { name: route, 89 | raw: File.read(examples[index]), 90 | examples: example_routes, 91 | } 92 | end 93 | puts "Registered route /#{route}".green 94 | end 95 | 96 | get '/' do 97 | erb :index, layout: false, locals: { examples: example_routes } 98 | end 99 | end 100 | 101 | run ExtensionsTestApplication 102 | -------------------------------------------------------------------------------- /spec/jenkinsdoc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'asciidoctor' 4 | require 'asciidoctor/jenkins/extensions' 5 | 6 | describe 'the jenkinsdoc macro' do 7 | subject(:rendering) { Asciidoctor.render(document) } 8 | 9 | context 'with a simple document' do 10 | let(:document) { 11 | "jenkinsdoc:hudson.scm.SCM[]" 12 | } 13 | 14 | it 'should render properly' do 15 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/hudson\/scm\/SCM.html.+>hudson.scm.SCM/) 16 | end 17 | end 18 | 19 | context 'with label' do 20 | let(:document) { 21 | "jenkinsdoc:hudson.scm.SCM[a list of all known SCM implementations]" 22 | } 23 | 24 | it 'should render properly' do 25 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/hudson\/scm\/SCM.html.+>a list of all known SCM implementations/) 26 | end 27 | end 28 | 29 | context 'with a fragment' do 30 | let(:document) { 31 | "jenkinsdoc:hudson.scm.SCM#all()[]" 32 | } 33 | 34 | it 'should render properly' do 35 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/hudson\/scm\/SCM.html#all--.+>hudson.scm.SCM/) 36 | end 37 | end 38 | 39 | context 'with a short name' do 40 | let(:document) { 41 | "jenkinsdoc:SCM[]" 42 | } 43 | 44 | it 'should render properly' do 45 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/byShortName\/SCM.+>SCM/) 46 | end 47 | end 48 | 49 | context 'with a plugin' do 50 | let(:document) { 51 | "jenkinsdoc:git:hudson.plugins.git.GitSCM[]" 52 | } 53 | it 'should render properly' do 54 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/plugin\/git\/hudson\/plugins\/git\/GitSCM.html.+>hudson.plugins.git.GitSCM/) 55 | end 56 | end 57 | 58 | context 'with a plugin and a fragment' do 59 | let(:document) { 60 | "jenkinsdoc:git:hudson.plugins.git.GitSCM#getRepositories()[]" 61 | } 62 | it 'should render properly' do 63 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/plugin\/git\/hudson\/plugins\/git\/GitSCM.html#getRepositories--.+>hudson.plugins.git.GitSCM/) 64 | end 65 | end 66 | 67 | context 'with a component' do 68 | let(:document) { 69 | "jenkinsdoc:component:remoting:hudson.remoting.Channel[]" 70 | } 71 | it 'should render properly' do 72 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/remoting\/hudson\/remoting\/Channel.html.+>hudson.remoting.Channel/) 73 | end 74 | end 75 | 76 | context 'with a component and a fragment' do 77 | let(:document) { 78 | "jenkinsdoc:component:remoting:hudson.remoting.Channel#classLoadingCount[]" 79 | } 80 | it 'should render properly' do 81 | expect(rendering).to match(/https:\/\/javadoc.jenkins.io\/component\/remoting\/hudson\/remoting\/Channel.html#classLoadingCount.+>hudson.remoting.Channel/) 82 | end 83 | end 84 | 85 | end -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/pipeline-block.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'colorize' 4 | require 'asciidoctor/extensions' 5 | require 'coderay' 6 | 7 | Asciidoctor::Extensions.register do 8 | block do 9 | named :pipeline 10 | on_context :listing 11 | name_positional_attributes 'format' 12 | 13 | process do |parent, reader, attrs| 14 | format = (attrs.delete('format') || '') 15 | codelines = reader.lines() 16 | script = nil 17 | declarative = nil 18 | 19 | # Find where our "// Script" comment is for highlighting the Pipeline 20 | # Script syntax 21 | script_index = codelines.find_index { |c| c.match(/\/\/ (script)(.*)?\/\//i) } || -1 22 | decl_index = codelines.find_index { |c| c.match(/\/\/ (declarative)(.*)?\/\//i) } || -1 23 | 24 | # It would be great to re-use the [source] block styling, but it turns 25 | # out that our parser is going to delete WHATEVER style attribute we 26 | # would give the block if we used #create_listing_block() 27 | # 28 | # Ouch: 29 | snippet = ['
'] 30 | 31 | if decl_index >= 0 32 | # Default to reading until the end of codelines 33 | last_line = -1 34 | 35 | if script_index > decl_index 36 | last_line = script_index - 1 37 | end 38 | declarative = codelines[(decl_index + 1) .. last_line].join("\n").chomp 39 | 40 | # If the declarative block is empty, we should just pretend it doesn't 41 | # exist. This is helpful for making notes/todos where Declarative isn't 42 | # applicable 43 | if declarative.empty? 44 | declarative = nil 45 | else 46 | declarative = CodeRay::Duo[:groovy, :html, { css: :style }].highlight(declarative) 47 | declarative = declarative.gsub(/\/\/ +<(\d+)>/) { 48 | m = $~ 49 | parent.document.callouts.register(m[1]) 50 | create_inline(parent, :callout, m[1], id: parent.document.callouts.read_next_id).convert 51 | } 52 | 53 | snippet << <<-EOF 54 |
55 |
Jenkinsfile (Declarative Pipeline)
56 |
57 | EOF 58 | snippet << <<-EOF 59 |
#{declarative}
60 | EOF 61 | snippet << '
' 62 | end 63 | end 64 | 65 | if script_index >= 0 66 | # Default to reading until the end of codelines 67 | last_line = -1 68 | 69 | # If our decl_index is lower than script_index, that means Declarative 70 | # was listed first, so we need to stop short of it 71 | if decl_index > script_index 72 | last_line = decl_index - 1 73 | end 74 | 75 | script = codelines[(script_index + 1) .. last_line].join("\n").chomp 76 | 77 | # If the script block is empty, we should just pretend it doesn't 78 | # exist. This is helpful for highlighting blocks where a script example 79 | # is yet to be written 80 | unless script.empty? 81 | # Since we have a declarative block, let's show that by default and 82 | # hide this but leave a bread-crumb 83 | unless declarative.nil? 84 | snippet << <<-EOF 85 |
86 | Toggle Scripted Pipeline 87 | (Advanced) 88 |
89 | EOF 90 | end 91 | 92 | script = CodeRay::Duo[:groovy, :html, { css: :style }].highlight(script) 93 | script = script.gsub(/\/\/ +<(\d+)>/) { 94 | m = $~ 95 | parent.document.callouts.register(m[1]) 96 | create_inline(parent, :callout, m[1], id: parent.document.callouts.read_next_id).convert 97 | } 98 | 99 | snippet << <<-EOF 100 |
102 |
Jenkinsfile (Scripted Pipeline)
103 |
104 | EOF 105 | snippet << <<-EOF 106 |
#{script}
107 | EOF 108 | snippet << '
' 109 | end 110 | end 111 | 112 | snippet << '
' 113 | 114 | # Fortunately Awestruct sets a handy docfile attribute so we can print a 115 | # useful warning 116 | docfile = parent.document.attributes['docfile'] 117 | 118 | if script_index < 0 119 | $stderr.puts "WARNING: [pipeline] block lacks `// Script //` section in #{docfile}".red 120 | end 121 | 122 | if decl_index < 0 123 | $stderr.puts "WARNING: [pipeline] block lacks `// Declarative //` section in #{docfile}".red 124 | end 125 | 126 | create_pass_block(parent, snippet.join(''), attrs) 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Asciidoctor::Jenkins::Extensions 2 | 3 | image::https://ci.jenkins.io/job/Infra/job/asciidoctor-jenkins-extensions/job/main/badge/icon["Build status", link="https://ci.jenkins.io/job/Infra/job/asciidoctor-jenkins-extensions/job/main"] 4 | 5 | 6 | This gem is a collection of Asciidoctor extensions which enable more advanced 7 | formatting in Jenkins-related content. 8 | 9 | 10 | == Installation 11 | 12 | Add this line to your application's Gemfile: 13 | 14 | [source,ruby] 15 | ---- 16 | gem 'asciidoctor-jenkins-extensions' 17 | ---- 18 | 19 | And then execute: 20 | 21 | $ bundle 22 | 23 | Or install it yourself as: 24 | 25 | $ gem install asciidoctor-jenkins-extensions 26 | 27 | == Usage 28 | 29 | Using this gem inside of an existing Asciidoctor-based project is as 30 | straight-forward as requiring `asciidoctor/jenkins/extensions`, for example: 31 | 32 | [source,ruby] 33 | ---- 34 | require 'asciidoctor/jenkins/extensions' 35 | ---- 36 | 37 | In link:http://awestruct.org[Awestruct]-based projects, this `require` 38 | statement should go in `_ext/pipeline.rb`. 39 | 40 | === [pipeline] block 41 | 42 | An extension to Asciidoctor syntax adds the `[pipeline]` block for including 43 | link:https://jenkins.io/doc/book/pipeline[Pipeline] code. This block supports 44 | both *Declarative Pipeline* and *Pipeline Script* syntax. For example: 45 | 46 | 47 | [source, asciidoc] 48 | -- 49 | [pipeline] 50 | ---- 51 | // Script // 52 | node { 53 | stage('Build') { 54 | checkout scm 55 | // Install dependencies 56 | sh 'npm install' 57 | } 58 | } 59 | 60 | // Declarative // 61 | pipeline { 62 | agent docker: 'node:6.3' 63 | stages { 64 | stage('Build') { 65 | sh 'npm install' 66 | } 67 | } 68 | } 69 | ---- 70 | -- 71 | 72 | This `pipeline` block will _prefer_ the Declarative Pipeline syntax when 73 | rendering, and provide a link for toggling the Scripted Pipeline. 74 | 75 | The `// Declarative //` or `// Script //` delimiters are *MANDATORY*, even when 76 | defining a `[pipeline]` block with only one syntax supported. These delimiters 77 | instruct the extension on how to render the given code. 78 | 79 | === the plugin macro 80 | 81 | The `plugin` inline macro can be used to link to plugins on the plugins index 82 | at https://plugins.jenkins.io/. 83 | 84 | Example: 85 | 86 | [source, asciidoc] 87 | ---- 88 | plugin:git[The Git Plugin] 89 | ---- 90 | 91 | === jenkinsdoc/staplerdoc/javadoc macros 92 | 93 | The `jenkinsdoc` inline macro can be used to link to the Jenkins Javadoc at https://javadoc.jenkins.io/. 94 | 95 | It supports a variety of different syntaxes. For classes in Jenkins core: 96 | 97 | * `jenkinsdoc:hudson.scm.SCM[]` links to the full URL for the class in Jenkins core. 98 | * `jenkinsdoc:hudson.scm.SCM#all()[]` links to the full URL for the class in Jenkins core, and includes a fragment. 99 | * `jenkinsdoc:SCM[]` links to the `/byShortName` URL for the class in Jenkins core. Due to the redirect, fragments won't work here. 100 | 101 | By default, all of these use the class name as label, but that can be customized if necessary by providing an alternative label between the square brackets. 102 | 103 | [source, asciidoc] 104 | ---- 105 | jenkinsdoc:hudson.scm.SCM#all()[a list of all known SCM implementations] 106 | ---- 107 | 108 | For classes in plugins, the plugin's name (`artifactId`) is put before the class name and separated by colon: 109 | 110 | * `jenkinsdoc:git:hudson.plugins.git.GitSCM[]` links to the full URL for the class in the git plugin. 111 | * `jenkinsdoc:git:hudson.plugins.git.GitSCM#getRepositories--[]` links to the full URL for the class in the git plugin, and includes a fragment. 112 | 113 | These use a similar default label if none is set, but it also specified which plugin the class is in. For the previous example, that label would be _hudson.plugins.git.GitSCM in git_. 114 | 115 | Two other inline macros, `staplerdoc` and `javadoc` exist and link to the Stapler API documentation and Java API documentation, respectively. 116 | These do not support the form of `jenkinsci` that only requires the short name, but otherwise work the same way. Examples: 117 | 118 | [source, asciidoc] 119 | ---- 120 | javadoc:java.io.File#pathSeparator[the path separator] 121 | staplerdoc:org.kohsuke.stapler.AncestorInPath[] 122 | ---- 123 | 124 | === Other macros (jep/jira/security) 125 | 126 | See [examples](./examples). 127 | 128 | == Development 129 | 130 | After checking out the repo, run `bin/setup` to install dependencies. You can 131 | also run `bin/console` for an interactive prompt that will allow you to 132 | experiment. 133 | 134 | To install this gem onto your local machine, run `bundle exec rake install`. To 135 | release a new version, update the version number in `version.rb`, and then run 136 | `bundle exec rake release`, which will create a git tag for the version, push 137 | git commits and tags, and push the `.gem` file to https://rubygems.org[rubygems.org]. 138 | 139 | 140 | === Acceptance Tests 141 | 142 | In order to make testing of extensions easier, there is a bit of support for 143 | live-page Asciidoc rendering with extensions live-reloaded on each page load. 144 | 145 | In the `examples/` directory you will find sample `.adoc` files which serve as 146 | test files for rendering with Asciidoctor and these extensions. To run the test 147 | server, assuming you have already executed `bundle install`, run: 148 | 149 | [source] 150 | ---- 151 | shotgun 152 | ---- 153 | 154 | And then navigate to link:http://localhost:9393/[localhost:9393] 155 | -------------------------------------------------------------------------------- /lib/asciidoctor/jenkins/extensions/javadoc-link.rb: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'asciidoctor/extensions' 3 | 4 | # 5 | # Usage: 6 | # 7 | # For core Javadoc: 8 | # 9 | # jenkinsdoc:SCM[] 10 | # jenkinsdoc:SCM[some label] 11 | # jenkinsdoc:hudson.scm.SCM[] 12 | # jenkinsdoc:hudson.scm.SCM[some label] 13 | # jenkinsdoc:hudson.scm.SCM#anchor[] 14 | # jenkinsdoc:hudson.scm.SCM#anchor[some label] 15 | # 16 | # 17 | # For plugin Javadoc: 18 | # 19 | # jenkinsdoc:git:hudson.plugins.git.GitSCM[] 20 | # jenkinsdoc:git:hudson.plugins.git.GitSCM[some label] 21 | # jenkinsdoc:git:hudson.plugins.git.GitSCM#anchor[] 22 | # jenkinsdoc:git:hudson.plugins.git.GitSCM#anchor[some label] 23 | # 24 | # 25 | # For component Javadoc: 26 | # 27 | # jenkinsdoc:component:remoting:hudson.remoting.Channel[] 28 | # jenkinsdoc:component:remoting:hudson.remoting.Channel[some label] 29 | # jenkinsdoc:component:remoting:hudson.remoting.Channel#anchor[] 30 | # jenkinsdoc:component:remoting:hudson.remoting.Channel#anchor[some label] 31 | 32 | Asciidoctor::Extensions.register do 33 | inline_macro do 34 | named :jenkinsdoc 35 | name_positional_attributes 'label' 36 | 37 | process do |parent, target, attrs| 38 | 39 | if target.include? ":" 40 | parts = target.split(':', 3) 41 | 42 | if parts.first == "component" 43 | component = parts[1] 44 | else 45 | plugin = parts.first 46 | end 47 | target = parts.last 48 | end 49 | classname = label = title = target 50 | 51 | package_parts = Array.new 52 | simpleclass_parts = Array.new 53 | 54 | is_package = true 55 | 56 | classname.split('.').each do |part| 57 | if is_package && /[[:lower:]]/.match(part[0]) 58 | package_parts.push(part) 59 | elsif match = /(.*)#/.match(part) 60 | class_part = match.captures 61 | simpleclass_parts.push(class_part) 62 | is_package = false 63 | 64 | # escape once fragment has been found, required for complex fragments that contain a '.' 65 | break 66 | else 67 | is_package = false 68 | simpleclass_parts.push(part) 69 | end 70 | end 71 | 72 | package = package_parts.join('.') 73 | simpleclass = simpleclass_parts.join('.') 74 | 75 | if package.length > 0 || plugin || component 76 | classname = classname.gsub(/#.*/, '') 77 | classurl = package.gsub(/\./, '/') + '/' + simpleclass + ".html" 78 | 79 | classfrag = (target.include? "#") ? '#' + target.gsub(/.*#/, '').gsub(/\(\)/, '--') : '' 80 | 81 | if plugin 82 | label = (attrs.has_key? 'label') ? attrs['label'] : %(#{classname} in #{plugin}) 83 | target = %(https://javadoc.jenkins.io/plugin/#{plugin}/#{classurl}#{classfrag}) 84 | elsif component 85 | label = (attrs.has_key? 'label') ? attrs['label'] : %(#{classname} in #{component}) 86 | target = %(https://javadoc.jenkins.io/component/#{component}/#{classurl}#{classfrag}) 87 | else 88 | label = (attrs.has_key? 'label') ? attrs['label'] : classname 89 | target = %(https://javadoc.jenkins.io/#{classurl}#{classfrag}) 90 | end 91 | else 92 | label = (attrs.has_key? 'label') ? attrs['label'] : classname 93 | target = %(https://javadoc.jenkins.io/byShortName/#{classname}) 94 | end 95 | 96 | title = %(Javadoc for #{classname}) 97 | 98 | (create_anchor parent, label, type: :link, target: target, attributes: { title: title }).render 99 | end 100 | end 101 | end 102 | 103 | Asciidoctor::Extensions.register do 104 | inline_macro do 105 | named :staplerdoc 106 | name_positional_attributes 'label' 107 | 108 | process do |parent, target, attrs| 109 | 110 | classname = target 111 | 112 | package_parts = Array.new 113 | simpleclass_parts = Array.new 114 | 115 | is_package = true 116 | 117 | classname.split('.').each do |part| 118 | match = /(.*)#/.match(part) 119 | if is_package && /[[:lower:]]/.match(part[0]) 120 | package_parts.push(part) 121 | elsif match = /(.*)#/.match(part) 122 | class_part = match.captures 123 | simpleclass_parts.push(class_part) 124 | is_package = false 125 | 126 | # escape once fragment has been found, required for complex fragments that contain a '.' 127 | break 128 | else 129 | is_package = false 130 | simpleclass_parts.push(part) 131 | end 132 | end 133 | 134 | package = package_parts.join('.') 135 | simpleclass = simpleclass_parts.join('.') 136 | 137 | classname = target.gsub(/#.*/, '') 138 | classurl = package.gsub(/\./, '/') + '/' + simpleclass + ".html" 139 | 140 | classfrag = (target.include? "#") ? '#' + target.gsub(/.*#/, '').gsub(/\(\)/, '--') : '' 141 | label = (attrs.has_key? 'label') ? attrs['label'] : classname 142 | target = %(https://javadoc.jenkins.io/component/stapler/#{classurl}#{classfrag}) 143 | 144 | title = %(Javadoc for #{classname}) 145 | 146 | (create_anchor parent, label, type: :link, target: target, attributes: { title: title }).render 147 | end 148 | end 149 | end 150 | 151 | 152 | Asciidoctor::Extensions.register do 153 | inline_macro do 154 | named :javadoc 155 | name_positional_attributes 'label' 156 | 157 | process do |parent, target, attrs| 158 | 159 | classname = target 160 | 161 | package_parts = Array.new 162 | simpleclass_parts = Array.new 163 | 164 | is_package = true 165 | 166 | classname.split('.').each do |part| 167 | if is_package && /[[:lower:]]/.match(part[0]) 168 | package_parts.push(part) 169 | elsif (match = /(.*)#/.match(part)) 170 | class_part = match.captures 171 | simpleclass_parts.push(class_part) 172 | is_package = false 173 | 174 | # escape once fragment has been found, required for complex fragments that contain a '.' 175 | break 176 | else 177 | is_package = false 178 | simpleclass_parts.push(part) 179 | end 180 | end 181 | 182 | package = package_parts.join('.') 183 | simpleclass = simpleclass_parts.join('.') 184 | 185 | classname = target.gsub(/#.*/, '') 186 | classurl = package.gsub(/\./, '/') + '/' + simpleclass + ".html" 187 | 188 | classfrag = (target.include? "#") ? '#' + target.gsub(/.*#/, '').gsub(/\(\)/, '--') : '' 189 | label = (attrs.has_key? 'label') ? attrs['label'] : classname 190 | target = %(https://docs.oracle.com/javase/8/docs/api/#{classurl}#{classfrag}) 191 | 192 | title = %(Javadoc for #{classname}) 193 | 194 | (create_anchor parent, label, type: :link, target: target, attributes: { title: title }).render 195 | end 196 | end 197 | end 198 | --------------------------------------------------------------------------------