{"action":"created","comment":{"url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/comments/59447670","id":59447670,"diff_hunk":"@@ -0,0 +1,258 @@\n+---\n+layout: post\n+title: Automating test runs on hardware with Pipeline-as-Code. Part 1\n+tags:\n+- jenkins\n+- jenkins2\n+- pipeline\n+- embedded\n+author: oleg_nenashev\n+---\n+\n+In addition to Jenkins development, during last 8 years I've been involved into continuous integration for hardware and embedded projects.\n+At JUC2015/London \n+link:https://www.cloudbees.com/jenkins/juc-2015/presentations/JUC-2015-Europe-Jenkins-Based-CI-for-Nenashev.pdf[I have conducted a talk] about common automation challenges in the area.\n+\n+In this blog post I would like to concentrate on link:https://jenkins.io/doc/pipeline/[Pipeline] (fka Workflow), which is a new automation-as-code ecosystem for Jenkins.\n+It will be proposed by default in the incoming link:/2.0/[Jenkins 2.0 release].\n+\n+First time I've tried Pipeline two and half years ago, and unfortunately it didn't work for my cases at all. \n+I was very disappointed and tried it only one year later, At this point the plugin became much more stable and useful. \n+It also attracted much more contributors, and it started evolving rapidly and finally became a huge ecosystem powered by Jenkins.\n+\n+Currently Pipeline is one of the best automation-as-code solutions available in automation servers, so I would like to highlight several Pipeline features, which may be interesting to Jenkins engineers working in the area.\n+\n+## Introduction\n+\n+In Embedded projects it's frequently required to run tests on specific hardware peripherals: development boards, prototypes, etc.\n+It may be required for both software and hardware areas, and especially for products involving both worlds.\n+CI and CD methodologies require continuous integration and system testing, and Jenkins comes to help here.\n+Jenkins is an automation framework, which can be adjusted to reliably work with hardware attached to its nodes.\n+\n+The classic automation approaches in Jenkins are based on Free-style and Multi-configuration project types. \n+Links to various articles on this topic are collected on the \n+link:/solutions/embedded/[HW/Embedded Solution page]Embedded on the Jenkins website.\n+Tests automation on hardware peripherals has been covered in several publications by Robert Martin, Steve Harris, JL Gray, Gordon McGregor, Martin d’Anjou, and Sarah Woodall.\n+There is also a top-level overview of classic approaches made by me at JUC2015/London (a bit outdated now).\n+\n+On the other hand, there is no previous publications, which would address Automation-as-code usage for the Embedded area.\n+In this post I want to address this use-case.\n+\n+## Area challenges\n+\n+Generally, any peripheral hardware device can be attached to a Jenkins node. \n+Since Jenkins nodes require Java only, almost every development machine can be attached.\n+Below you can find a common connection scheme:\n+\n+image::/images/blog/pipeline-as-code-for-hardware/connectBoard.png[\"Connecting the external device\", width=550, align=\"center\"]\n+\n+After the connection, Jenkins jobs could invoke common EDA tools via command-line interfaces.\n+It can be easily done by a _Execute shell_ build steps in free-style projects.\n+Such testing scheme is commonly affected by the following issues:\n+\n+* Nodes with peripherals are being shared across several projects. \n+Jenkins must insure the correctness of access (e.g. by throttling the access). \n+** In a single Freestyle project builds utilize the node for a long period. If you synthesize the item before the run, much of the peripheral utilization file may be wasted.\n+** The issue can be solved by one of concurrency management plugins:\n+link:https://wiki.jenkins-ci.org/display/JENKINS/Throttle+Concurrent+Builds+Plugin[Throttle Concurrent Builds], link:https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin[Lockable Resources]\n+ or \n+link:https://wiki.jenkins-ci.org/display/JENKINS/Exclusion-Plugin[Exclusions].\n+* Test parallelization on multiple nodes requires using of multiple projects or \n+link:https://wiki.jenkins-ci.org/display/JENKINS/Matrix+Project+Plugin[Matrix configurations], so it causes job chaining again.\n+** These build chains can be created via \n+link:https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Trigger+Plugin[Parameterized Trigger] and \n+link:https://wiki.jenkins-ci.org/display/JENKINS/Copy+Artifact+Plugin[Copy Artifacts], but it complicates job management and build history investigation.\n+* Hardware infrastructure is usually flaky. \n+If it fails during the build due to any reason, it's hard to diagnose the issue and re-run the project if the issue comes from hardware.\n+** link:https://wiki.jenkins-ci.org/display/JENKINS/Build+Failure+Analyzer[Build Failure Analyzer] allows to identify the root cause of a build failure (e.g. by build log parsing).\n+** link:https://wiki.jenkins-ci.org/display/JENKINS/Conditional+BuildStep+Plugin[Conditional Build Step] and \n+link:https://wiki.jenkins-ci.org/display/JENKINS/Flexible+Publish+Plugin[Flexible Publish] plugins allow altering the build flow according to the analysis results.\n+** Combination of the plugins above is possible, but it makes job configurations extremely large.\n+* Tests on hardware peripherals may take much time. \n+If an infrastructure fails, we may have to restart the run from scratch. \n+So the builds should be robust against infrastructure issues including network failures and Jenkins master restarts.\n+* Tests on hardware should be reproducible, so the environment and input parameters should be controlled well.\n+** Jenkins supports\n+link:https://wiki.jenkins-ci.org/display/JENKINS/Workspace+Cleanup+Plugin[cleaning workspaces], so it can get rid of temporary files generated by previous runs.\n+** Jenkins provides support of slaves connected via containers (e.g. \n+  link:https://wiki.jenkins-ci.org/display/JENKINS/Docker+Plugin[Docker]) or VMs, which allow creating clean environments for every new run.\n+It's important for 3rd-party tools, which may modify files outside the workspace: user home directory, temporary files, etc.\n+** These environments still need to be connected to hardware peripherals, which may be a serious obstacle for Jenkins admins\n+\n+Usage of \n+link:https://jenkins.io/doc/pipeline/[Jenkins Pipeline]  can effectively address the use-cases above.\n+In this blogpost I want to address several cases.\n+\n+## Pipeline-as-Code for test runs on hardware\n+\n+Pipeline-as-Code is an emerging technology for representing job configurations as code.","path":"content/blog/2016/2016-04-07-pipeline-for-runs-on-hardware.adoc","position":88,"original_position":88,"commit_id":"331a1dc81f49ced94e4430c9a40c323faaffb586","original_commit_id":"331a1dc81f49ced94e4430c9a40c323faaffb586","user":{"login":"oleg-nenashev","id":3000480,"avatar_url":"https://avatars.githubusercontent.com/u/3000480?v=3","gravatar_id":"","url":"https://api.github.com/users/oleg-nenashev","html_url":"https://github.com/oleg-nenashev","followers_url":"https://api.github.com/users/oleg-nenashev/followers","following_url":"https://api.github.com/users/oleg-nenashev/following{/other_user}","gists_url":"https://api.github.com/users/oleg-nenashev/gists{/gist_id}","starred_url":"https://api.github.com/users/oleg-nenashev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oleg-nenashev/subscriptions","organizations_url":"https://api.github.com/users/oleg-nenashev/orgs","repos_url":"https://api.github.com/users/oleg-nenashev/repos","events_url":"https://api.github.com/users/oleg-nenashev/events{/privacy}","received_events_url":"https://api.github.com/users/oleg-nenashev/received_events","type":"User","site_admin":false},"body":"@rtyler \r\nPipeline as Code is an approach for describing complex automation flows in software lifecycles: build, delivery, deployment, etc. It is being advertised in Continuous Delivery and DevOps methodologies.\r\n\r\nWDYT?","created_at":"2016-04-12T20:29:40Z","updated_at":"2016-04-12T20:29:40Z","html_url":"https://github.com/jenkins-infra/jenkins.io/pull/195#discussion_r59447670","pull_request_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195","_links":{"self":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/comments/59447670"},"html":{"href":"https://github.com/jenkins-infra/jenkins.io/pull/195#discussion_r59447670"},"pull_request":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195"}}},"pull_request":{"url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195","id":65624310,"html_url":"https://github.com/jenkins-infra/jenkins.io/pull/195","diff_url":"https://github.com/jenkins-infra/jenkins.io/pull/195.diff","patch_url":"https://github.com/jenkins-infra/jenkins.io/pull/195.patch","issue_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/195","number":195,"state":"open","locked":false,"title":"Automating test runs on hardware with Pipeline-as-Code","user":{"login":"oleg-nenashev","id":3000480,"avatar_url":"https://avatars.githubusercontent.com/u/3000480?v=3","gravatar_id":"","url":"https://api.github.com/users/oleg-nenashev","html_url":"https://github.com/oleg-nenashev","followers_url":"https://api.github.com/users/oleg-nenashev/followers","following_url":"https://api.github.com/users/oleg-nenashev/following{/other_user}","gists_url":"https://api.github.com/users/oleg-nenashev/gists{/gist_id}","starred_url":"https://api.github.com/users/oleg-nenashev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oleg-nenashev/subscriptions","organizations_url":"https://api.github.com/users/oleg-nenashev/orgs","repos_url":"https://api.github.com/users/oleg-nenashev/repos","events_url":"https://api.github.com/users/oleg-nenashev/events{/privacy}","received_events_url":"https://api.github.com/users/oleg-nenashev/received_events","type":"User","site_admin":false},"body":"This is a draft version of the blog-post.\r\nI consider adding several extra examples. BTW it may make the post too overloaded.\r\n\r\nCC @jenkins-infra/copy-editors @martinda","created_at":"2016-04-07T12:51:15Z","updated_at":"2016-04-12T20:29:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8c5c5f74330c802fe1ca5bd0b90e944aada7bc32","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195/commits","review_comments_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195/comments","review_comment_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/195/comments","statuses_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/statuses/331a1dc81f49ced94e4430c9a40c323faaffb586","head":{"label":"oleg-nenashev:pipeline_embedded_blog","ref":"pipeline_embedded_blog","sha":"331a1dc81f49ced94e4430c9a40c323faaffb586","user":{"login":"oleg-nenashev","id":3000480,"avatar_url":"https://avatars.githubusercontent.com/u/3000480?v=3","gravatar_id":"","url":"https://api.github.com/users/oleg-nenashev","html_url":"https://github.com/oleg-nenashev","followers_url":"https://api.github.com/users/oleg-nenashev/followers","following_url":"https://api.github.com/users/oleg-nenashev/following{/other_user}","gists_url":"https://api.github.com/users/oleg-nenashev/gists{/gist_id}","starred_url":"https://api.github.com/users/oleg-nenashev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oleg-nenashev/subscriptions","organizations_url":"https://api.github.com/users/oleg-nenashev/orgs","repos_url":"https://api.github.com/users/oleg-nenashev/repos","events_url":"https://api.github.com/users/oleg-nenashev/events{/privacy}","received_events_url":"https://api.github.com/users/oleg-nenashev/received_events","type":"User","site_admin":false},"repo":{"id":48843822,"name":"jenkins.io","full_name":"oleg-nenashev/jenkins.io","owner":{"login":"oleg-nenashev","id":3000480,"avatar_url":"https://avatars.githubusercontent.com/u/3000480?v=3","gravatar_id":"","url":"https://api.github.com/users/oleg-nenashev","html_url":"https://github.com/oleg-nenashev","followers_url":"https://api.github.com/users/oleg-nenashev/followers","following_url":"https://api.github.com/users/oleg-nenashev/following{/other_user}","gists_url":"https://api.github.com/users/oleg-nenashev/gists{/gist_id}","starred_url":"https://api.github.com/users/oleg-nenashev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oleg-nenashev/subscriptions","organizations_url":"https://api.github.com/users/oleg-nenashev/orgs","repos_url":"https://api.github.com/users/oleg-nenashev/repos","events_url":"https://api.github.com/users/oleg-nenashev/events{/privacy}","received_events_url":"https://api.github.com/users/oleg-nenashev/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/oleg-nenashev/jenkins.io","description":"A static site for the Jenkins automation server","fork":true,"url":"https://api.github.com/repos/oleg-nenashev/jenkins.io","forks_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/forks","keys_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/teams","hooks_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/hooks","issue_events_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/issues/events{/number}","events_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/events","assignees_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/assignees{/user}","branches_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/branches{/branch}","tags_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/tags","blobs_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/statuses/{sha}","languages_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/languages","stargazers_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/stargazers","contributors_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/contributors","subscribers_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/subscribers","subscription_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/subscription","commits_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/contents/{+path}","compare_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/merges","archive_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/downloads","issues_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/issues{/number}","pulls_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/pulls{/number}","milestones_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/milestones{/number}","notifications_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/labels{/name}","releases_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/releases{/id}","deployments_url":"https://api.github.com/repos/oleg-nenashev/jenkins.io/deployments","created_at":"2015-12-31T09:26:28Z","updated_at":"2015-12-31T09:26:30Z","pushed_at":"2016-04-11T21:29:10Z","git_url":"git://github.com/oleg-nenashev/jenkins.io.git","ssh_url":"git@github.com:oleg-nenashev/jenkins.io.git","clone_url":"https://github.com/oleg-nenashev/jenkins.io.git","svn_url":"https://github.com/oleg-nenashev/jenkins.io","homepage":"http://beta.jenkins.io","size":37203,"stargazers_count":0,"watchers_count":0,"language":"HTML","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"jenkins-infra:master","ref":"master","sha":"ebd835c72d6e86918128252c369e8ed311784b54","user":{"login":"jenkins-infra","id":7422698,"avatar_url":"https://avatars.githubusercontent.com/u/7422698?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkins-infra","html_url":"https://github.com/jenkins-infra","followers_url":"https://api.github.com/users/jenkins-infra/followers","following_url":"https://api.github.com/users/jenkins-infra/following{/other_user}","gists_url":"https://api.github.com/users/jenkins-infra/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkins-infra/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkins-infra/subscriptions","organizations_url":"https://api.github.com/users/jenkins-infra/orgs","repos_url":"https://api.github.com/users/jenkins-infra/repos","events_url":"https://api.github.com/users/jenkins-infra/events{/privacy}","received_events_url":"https://api.github.com/users/jenkins-infra/received_events","type":"Organization","site_admin":false},"repo":{"id":44886691,"name":"jenkins.io","full_name":"jenkins-infra/jenkins.io","owner":{"login":"jenkins-infra","id":7422698,"avatar_url":"https://avatars.githubusercontent.com/u/7422698?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkins-infra","html_url":"https://github.com/jenkins-infra","followers_url":"https://api.github.com/users/jenkins-infra/followers","following_url":"https://api.github.com/users/jenkins-infra/following{/other_user}","gists_url":"https://api.github.com/users/jenkins-infra/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkins-infra/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkins-infra/subscriptions","organizations_url":"https://api.github.com/users/jenkins-infra/orgs","repos_url":"https://api.github.com/users/jenkins-infra/repos","events_url":"https://api.github.com/users/jenkins-infra/events{/privacy}","received_events_url":"https://api.github.com/users/jenkins-infra/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jenkins-infra/jenkins.io","description":"A static site for the Jenkins automation server","fork":false,"url":"https://api.github.com/repos/jenkins-infra/jenkins.io","forks_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/forks","keys_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/teams","hooks_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/hooks","issue_events_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/events{/number}","events_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/events","assignees_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/assignees{/user}","branches_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/branches{/branch}","tags_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/tags","blobs_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/statuses/{sha}","languages_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/languages","stargazers_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/stargazers","contributors_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/contributors","subscribers_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/subscribers","subscription_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/subscription","commits_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/contents/{+path}","compare_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/merges","archive_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/downloads","issues_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues{/number}","pulls_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls{/number}","milestones_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/milestones{/number}","notifications_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/labels{/name}","releases_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/releases{/id}","deployments_url":"https://api.github.com/repos/jenkins-infra/jenkins.io/deployments","created_at":"2015-10-24T22:02:57Z","updated_at":"2016-03-28T22:22:28Z","pushed_at":"2016-04-12T19:35:18Z","git_url":"git://github.com/jenkins-infra/jenkins.io.git","ssh_url":"git@github.com:jenkins-infra/jenkins.io.git","clone_url":"https://github.com/jenkins-infra/jenkins.io.git","svn_url":"https://github.com/jenkins-infra/jenkins.io","homepage":"https://jenkins.io","size":43529,"stargazers_count":14,"watchers_count":14,"language":"HTML","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":57,"mirror_url":null,"open_issues_count":5,"forks":57,"open_issues":5,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195"},"html":{"href":"https://github.com/jenkins-infra/jenkins.io/pull/195"},"issue":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/195"},"comments":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/issues/195/comments"},"review_comments":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195/comments"},"review_comment":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/pulls/195/commits"},"statuses":{"href":"https://api.github.com/repos/jenkins-infra/jenkins.io/statuses/331a1dc81f49ced94e4430c9a40c323faaffb586"}}}}