diff --git a/html/404.html b/html/404.html index db240505..89d73c32 100644 --- a/html/404.html +++ b/html/404.html @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + @@ -1088,10 +1088,10 @@

404 - Not found

- + - + diff --git a/html/assets/javascripts/bundle.220ee61c.min.js b/html/assets/javascripts/bundle.220ee61c.min.js new file mode 100644 index 00000000..116072a1 --- /dev/null +++ b/html/assets/javascripts/bundle.220ee61c.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + - + diff --git a/html/libraries/edgeXBuildCApp/index.html b/html/libraries/edgeXBuildCApp/index.html index f15c37a2..a0dad88c 100644 --- a/html/libraries/edgeXBuildCApp/index.html +++ b/html/libraries/edgeXBuildCApp/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1427,10 +1427,10 @@

Full example

- + - + diff --git a/html/libraries/edgeXBuildDocker/index.html b/html/libraries/edgeXBuildDocker/index.html index 3e391744..4c072e1c 100644 --- a/html/libraries/edgeXBuildDocker/index.html +++ b/html/libraries/edgeXBuildDocker/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1418,10 +1418,10 @@

Full example

- + - + diff --git a/html/libraries/edgeXBuildGoApp/index.html b/html/libraries/edgeXBuildGoApp/index.html index 8b93780d..2a3405fb 100644 --- a/html/libraries/edgeXBuildGoApp/index.html +++ b/html/libraries/edgeXBuildGoApp/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1486,10 +1486,10 @@

Full example

- + - + diff --git a/html/libraries/edgeXBuildGoMod/index.html b/html/libraries/edgeXBuildGoMod/index.html index 31a1f792..35ec3c3b 100644 --- a/html/libraries/edgeXBuildGoMod/index.html +++ b/html/libraries/edgeXBuildGoMod/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1154,7 +1154,7 @@

Parameters

pushImage: false, semverBump: 'pre' - Note: These parameters are not overridable.

+** Note:** These parameters are not overridable.

Usage

Basic example

edgeXBuildGoMod (
@@ -1270,10 +1270,10 @@ 

Full example

- + - + diff --git a/html/libraries/edgeXBuildGoParallel/index.html b/html/libraries/edgeXBuildGoParallel/index.html index df8278d7..179c02cb 100644 --- a/html/libraries/edgeXBuildGoParallel/index.html +++ b/html/libraries/edgeXBuildGoParallel/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1458,10 +1458,10 @@

Full example

- + - + diff --git a/html/libraries/edgeXClair/index.html b/html/libraries/edgeXClair/index.html index 87bdb18f..5edcaf50 100644 --- a/html/libraries/edgeXClair/index.html +++ b/html/libraries/edgeXClair/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1126,10 +1126,10 @@

edgeXClair

- + - + diff --git a/html/libraries/edgeXCodecov/index.html b/html/libraries/edgeXCodecov/index.html index 469141b4..c12b1927 100644 --- a/html/libraries/edgeXCodecov/index.html +++ b/html/libraries/edgeXCodecov/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1222,10 +1222,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXDocker/index.html b/html/libraries/edgeXDocker/index.html index 090c927d..ce16e62f 100644 --- a/html/libraries/edgeXDocker/index.html +++ b/html/libraries/edgeXDocker/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1224,10 +1224,10 @@

Parsed image object

- + - + diff --git a/html/libraries/edgeXDockerLogin/index.html b/html/libraries/edgeXDockerLogin/index.html index 257b7943..b9e77815 100644 --- a/html/libraries/edgeXDockerLogin/index.html +++ b/html/libraries/edgeXDockerLogin/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1249,10 +1249,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXEmail/index.html b/html/libraries/edgeXEmail/index.html index bce1968d..6fc57922 100644 --- a/html/libraries/edgeXEmail/index.html +++ b/html/libraries/edgeXEmail/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1228,10 +1228,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXEmailUtil/index.html b/html/libraries/edgeXEmailUtil/index.html index afee0429..f583e9e3 100644 --- a/html/libraries/edgeXEmailUtil/index.html +++ b/html/libraries/edgeXEmailUtil/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1211,10 +1211,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXGHPagesPublish/index.html b/html/libraries/edgeXGHPagesPublish/index.html index 6f5ffa7a..8f38e49e 100644 --- a/html/libraries/edgeXGHPagesPublish/index.html +++ b/html/libraries/edgeXGHPagesPublish/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1264,10 +1264,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXGeneric/index.html b/html/libraries/edgeXGeneric/index.html index 44295ffd..e33c51e5 100644 --- a/html/libraries/edgeXGeneric/index.html +++ b/html/libraries/edgeXGeneric/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1149,10 +1149,10 @@

edgeXGeneric

- + - + diff --git a/html/libraries/edgeXInfraLFToolsSign/index.html b/html/libraries/edgeXInfraLFToolsSign/index.html index 8fa46b18..35aae086 100644 --- a/html/libraries/edgeXInfraLFToolsSign/index.html +++ b/html/libraries/edgeXInfraLFToolsSign/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1270,10 +1270,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXInfraPublish/index.html b/html/libraries/edgeXInfraPublish/index.html index 69dc4523..d060f88b 100644 --- a/html/libraries/edgeXInfraPublish/index.html +++ b/html/libraries/edgeXInfraPublish/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1233,10 +1233,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXInfraShipLogs/index.html b/html/libraries/edgeXInfraShipLogs/index.html index dd44d925..7ed2e2fa 100644 --- a/html/libraries/edgeXInfraShipLogs/index.html +++ b/html/libraries/edgeXInfraShipLogs/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1125,10 +1125,10 @@

edgeXInfraPublish

- + - + diff --git a/html/libraries/edgeXLTS/index.html b/html/libraries/edgeXLTS/index.html index 32b1c6d2..06897880 100644 --- a/html/libraries/edgeXLTS/index.html +++ b/html/libraries/edgeXLTS/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1193,10 +1193,10 @@

Functions:

- + - + diff --git a/html/libraries/edgeXNexusPublish/index.html b/html/libraries/edgeXNexusPublish/index.html index 99d21f0b..550c3584 100644 --- a/html/libraries/edgeXNexusPublish/index.html +++ b/html/libraries/edgeXNexusPublish/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1246,10 +1246,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXRelease/index.html b/html/libraries/edgeXRelease/index.html index 86ae5d9a..fe1ca6c6 100644 --- a/html/libraries/edgeXRelease/index.html +++ b/html/libraries/edgeXRelease/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1264,10 +1264,10 @@

Functions

- + - + diff --git a/html/libraries/edgeXReleaseDockerImage/index.html b/html/libraries/edgeXReleaseDockerImage/index.html index 07ca66da..511c6708 100644 --- a/html/libraries/edgeXReleaseDockerImage/index.html +++ b/html/libraries/edgeXReleaseDockerImage/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1304,10 +1304,10 @@

Groovy Call

- + - + diff --git a/html/libraries/edgeXReleaseDocs/index.html b/html/libraries/edgeXReleaseDocs/index.html index 4957117e..9cb6006e 100644 --- a/html/libraries/edgeXReleaseDocs/index.html +++ b/html/libraries/edgeXReleaseDocs/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1302,10 +1302,10 @@

Groovy Call

- + - + diff --git a/html/libraries/edgeXReleaseGitHubAssets/index.html b/html/libraries/edgeXReleaseGitHubAssets/index.html index 39121005..a2b56031 100644 --- a/html/libraries/edgeXReleaseGitHubAssets/index.html +++ b/html/libraries/edgeXReleaseGitHubAssets/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1290,10 +1290,10 @@

Groovy Call

- + - + diff --git a/html/libraries/edgeXReleaseGitTag/index.html b/html/libraries/edgeXReleaseGitTag/index.html index 859d39c4..b96f9fb0 100644 --- a/html/libraries/edgeXReleaseGitTag/index.html +++ b/html/libraries/edgeXReleaseGitTag/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1284,10 +1284,10 @@

Groovy Call

- + - + diff --git a/html/libraries/edgeXReleaseGitTagUtil/index.html b/html/libraries/edgeXReleaseGitTagUtil/index.html index c57652ab..fd2df97d 100644 --- a/html/libraries/edgeXReleaseGitTagUtil/index.html +++ b/html/libraries/edgeXReleaseGitTagUtil/index.html @@ -17,7 +17,7 @@ - + @@ -25,7 +25,7 @@ - + @@ -1139,10 +1139,10 @@

Functions

- + - + diff --git a/html/libraries/edgeXReleaseOpenApi/index.html b/html/libraries/edgeXReleaseOpenApi/index.html index 1d86db94..d86af05d 100644 --- a/html/libraries/edgeXReleaseOpenApi/index.html +++ b/html/libraries/edgeXReleaseOpenApi/index.html @@ -17,7 +17,7 @@ - + @@ -25,7 +25,7 @@ - + @@ -1209,10 +1209,10 @@

Groovy Call

- + - + diff --git a/html/libraries/edgeXReleaseSnap/index.html b/html/libraries/edgeXReleaseSnap/index.html index 76db3709..50da6aa3 100644 --- a/html/libraries/edgeXReleaseSnap/index.html +++ b/html/libraries/edgeXReleaseSnap/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1125,10 +1125,10 @@

edgeXReleaseSnap

- + - + diff --git a/html/libraries/edgeXSemver/index.html b/html/libraries/edgeXSemver/index.html index 5452ad86..2def5e1d 100644 --- a/html/libraries/edgeXSemver/index.html +++ b/html/libraries/edgeXSemver/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1271,10 +1271,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXSetupEnvironment/index.html b/html/libraries/edgeXSetupEnvironment/index.html index 3a9972f2..fdd8c41c 100644 --- a/html/libraries/edgeXSetupEnvironment/index.html +++ b/html/libraries/edgeXSetupEnvironment/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1234,10 +1234,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXSnap/index.html b/html/libraries/edgeXSnap/index.html index 0fa17b8b..59fd9a29 100644 --- a/html/libraries/edgeXSnap/index.html +++ b/html/libraries/edgeXSnap/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1190,10 +1190,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXSnyk/index.html b/html/libraries/edgeXSnyk/index.html index d861661f..39b2815e 100644 --- a/html/libraries/edgeXSnyk/index.html +++ b/html/libraries/edgeXSnyk/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1279,10 +1279,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXSwaggerPublish/index.html b/html/libraries/edgeXSwaggerPublish/index.html index d44f0361..41686d1f 100644 --- a/html/libraries/edgeXSwaggerPublish/index.html +++ b/html/libraries/edgeXSwaggerPublish/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1242,10 +1242,10 @@

Usage

- + - + diff --git a/html/libraries/edgeXUpdateNamedTag/index.html b/html/libraries/edgeXUpdateNamedTag/index.html index 042dcedf..226ab66d 100644 --- a/html/libraries/edgeXUpdateNamedTag/index.html +++ b/html/libraries/edgeXUpdateNamedTag/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1237,10 +1237,10 @@

Usage

- + - + diff --git a/html/libraries/edgex/index.html b/html/libraries/edgex/index.html index 91af9a38..3042b357 100644 --- a/html/libraries/edgex/index.html +++ b/html/libraries/edgex/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1228,10 +1228,10 @@

Functions

- + - + diff --git a/html/releases/jakarta-lts-initial/index.html b/html/releases/jakarta-lts-initial/index.html index 6920472f..fe0e6b52 100644 --- a/html/releases/jakarta-lts-initial/index.html +++ b/html/releases/jakarta-lts-initial/index.html @@ -19,7 +19,7 @@ - + @@ -27,7 +27,7 @@ - + @@ -1416,10 +1416,10 @@

Semver notes and noop builds

- + - + diff --git a/html/releases/jakarta-release-stages/index.html b/html/releases/jakarta-release-stages/index.html index 836ae606..7d13f4fe 100644 --- a/html/releases/jakarta-release-stages/index.html +++ b/html/releases/jakarta-release-stages/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1410,10 +1410,10 @@

Main branch (Regular Dev Process)

- + - + diff --git a/html/search/search_index.json b/html/search/search_index.json index 0d04ae27..76e99671 100644 --- a/html/search/search_index.json +++ b/html/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"EdgeX Global Pipelines","text":""},{"location":"#summary","title":"Summary","text":"

This repository contains useful Jenkins global library functions used within the EdgeX Jenkins ecosystem. It provides pre-built pipelines to build and publish Go/C++ based source code in a consistent manner. There are also a lot of utility functions that allow for things like automated vulnerability scanning via Snyk, code coverage tracking via CodeCov.io and many other things. Below you will find some useful links as well as links to all of our documented pipelines.

Please note: Documentation is still under heavy development.

"},{"location":"#useful-links","title":"Useful Links","text":"
  • Source Code
  • EdgeX Jenkins Server
  • Jenkins Shared Libraries
"},{"location":"#jenkins-shared-libraries","title":"Jenkins Shared Libraries","text":"
  • edgeXBuildCApp
  • edgeXBuildDocker
  • edgeXBuildGoApp
  • edgeXBuildGoMod
  • edgeXBuildGoParallel
  • edgeXClair
  • edgeXCodecov
  • edgeXDocker
  • edgeXDockerLogin
  • edgeXEmail
  • edgeXEmailUtil
  • edgeXGHPagesPublish
  • edgeXGeneric
  • edgeXInfraLFToolsSign
  • edgeXInfraPublish
  • edgeXInfraShipLogs
  • edgeXLTS
  • edgeXNexusPublish
  • edgeXRelease
  • edgeXReleaseDockerImage
  • edgeXReleaseDocs
  • edgeXReleaseGitHubAssets
  • edgeXReleaseGitTag
  • edgeXReleaseGitTagUtil
  • edgeXReleaseOpenApi
  • edgeXReleaseSnap
  • edgeXSemver
  • edgeXSetupEnvironment
  • edgeXSnap
  • edgeXSnyk
  • edgeXSwaggerPublish
  • edgeXUpdateNamedTag
  • edgex
"},{"location":"libraries/edgeXBuildCApp/","title":"edgeXBuildCApp","text":"

Shared Library to build C projects

"},{"location":"libraries/edgeXBuildCApp/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildCApp/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build dockerBaseImage optional str The docker base image for your project.Default: nexus3.edgexfoundry.org:10003/edgex-devops/edgex-gcc-base:latest dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to false.Default: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildCApp/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildCApp/#basic-example","title":"Basic example","text":"
edgeXBuildCApp (\nproject: 'device-bacnet-c'\n)\n
"},{"location":"libraries/edgeXBuildCApp/#complex-example","title":"Complex example","text":"
edgeXBuildCApp (\nproject: 'device-sdk-c',\ndockerBuildFilePath: 'scripts/Dockerfile.alpine-3.11-base',\ndockerFilePath: 'scripts/Dockerfile.alpine-3.11',\ntestScript: 'apk add --update --no-cache openssl ca-certificates && make test',\npushImage: false\n)\n
"},{"location":"libraries/edgeXBuildCApp/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildCApp (\nproject: 'c-project',\nmavenSettings: 'c-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ndockerBaseImage: 'nexus3.edgexfoundry.org:10003/edgex-devops/edgex-gcc-base:latest',\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-c-project',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildDocker/","title":"edgeXBuildDocker","text":"

Shared Library to build docker images

"},{"location":"libraries/edgeXBuildDocker/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildDocker/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerTags optional str The tag name for your docker image.Default: [] dockerPushLatest optional str Specify if Jenkins should push the docker image with latest tag. Default: true dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true archiveImage optional bool Specify if the built image need to be archived.Default: false archiveName optional bool The name of the archived image.Default: ${_projectName}-archive.tar.gz semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre releaseBranchOverride optional str Specify if you want to override the release branch. failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildDocker/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildDocker/#basic-example","title":"Basic example","text":"
edgeXBuildDocker (\nproject: 'docker-edgex-consul',\ndockerImageName: 'docker-edgex-consul',\nsemver: true\n)\n
"},{"location":"libraries/edgeXBuildDocker/#complex-example","title":"Complex example","text":"
edgeXBuildDocker (\nproject: 'edgex-compose',\nmavenSettings: 'ci-build-images-settings',\ndockerImageName: 'custom-edgex-compose',\ndockerNamespace: 'edgex-devops',\ndockerNexusRepo: 'snapshots',\ndockerTags: [\"1.24.1\"],\nreleaseBranchOverride: 'edgex-compose'\n)\n
"},{"location":"libraries/edgeXBuildDocker/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildDocker (\nproject: 'sample-project',\nmavenSettings: 'sample-project-settings',\nsemver: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-sample-project',\ndockerTags: [],\ndockerPushLatest: true,\ndockerNexusRepo: 'staging',\npushImage: true,\narchiveImage: false,\narchiveName: sample-project-archive.tar.gz,\nsemverBump: 'pre',\nreleaseBranchOverride: 'golang',\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildGoApp/","title":"edgeXBuildGoApp","text":"

Shared Library to build Go projects

"},{"location":"libraries/edgeXBuildGoApp/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildGoApp/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build goVersion optional str The version of Go to use for building the project's CI build image. Note this parameter is used in conjuction with the useAlpineBase parameter to determine the base for the project's CI build image.Default: 1.20 goProxy optional str The proxy to use when downloading Go modules. The value of this parameter will be set in the GOPROXY environment variable to control the download source of Go modules.Default: https://nexus3.edgexfoundry.org/repository/go-proxy/ useAlpineBase optional bool Specify if an Alpine-based edgex-golang-base:${goVersion}-alpine image will be used as the base for the project's CI build image. If true, the respective edgex-golang-base image should exist in the Nexus snapshot repository, if a matching image is not found in Nexus then an Alpine-based go-lang:${goVersion}-alpine DockerHub image will be used. If false, then a non-Alpine go-lang:${goVersion} DockerHub image will be used. Note this parameter is used in conjuction with the goVersion parameter to determine the base for the projects' CI build image.Default: true dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to false.Default: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre semverVersion optional str This parameter isn't currently used and will be removed in a future version.Default: '' buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false publishSwaggerDocs optional bool Specify if Jenkins should attempt to publish your projects API documentation to SwaggerHub. Note in order for Jenkins to publish to SwaggerHub you must ensure a valid value for swaggerApiFolders is set.Default: false swaggerApiFolders optional list The list of paths to your projects API Swagger-based documentation.Default: ['openapi/v1'] failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org buildExperimentalDockerImage optional bool Specify if Jenkins should add an additonal GitHub tag called experimental at the same commit where the semantic version is tagged. Note this feature is currently only used internally for DevOps builds.Default: false artifactTypes optional list A list of types that the Jenkins build will designate as artifacts, valid list values are docker and archive. Note if archive is specified then all tar.gz or zip files that your project build creates in the artifactRoot folder will be archived to Nexus.Default: ['docker'] artifactRoot optional str The path in the Jenkins workspace to designate as the artifact root folder. Note all files written to this directory within your build will be automatically pushed to Nexus when the Jenkins job completes.Default: archives/bin arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildGoApp/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoApp/#basic-example","title":"Basic example","text":"
edgeXBuildGoApp (\nproject: 'device-random-go',\ngoVersion: '1.16'\n)\n
"},{"location":"libraries/edgeXBuildGoApp/#complex-example","title":"Complex example","text":"
edgeXBuildGoApp (\nproject: 'app-functions-sdk-go',\nsemver: true,\ngoVersion: '1.16',\ntestScript: 'make test',\nbuildImage: false,\npublishSwaggerDocs: true,\nswaggerApiFolders: ['openapi/v2']\n)\n
"},{"location":"libraries/edgeXBuildGoApp/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoApp (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-go-project',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\nbuildExperimentalDockerImage: false,\nartifactTypes: ['docker'],\nartifactRoot: 'archives/bin',\narch: ['amd64', 'arm64']\n\n)\n
"},{"location":"libraries/edgeXBuildGoMod/","title":"edgeXBuildGoMod","text":"

Shared Library to build Go projects using Go Modules. It invokes edgeXBuildGoApp with some default parameters.

"},{"location":"libraries/edgeXBuildGoMod/#parameters","title":"Parameters","text":"

The parameters are similar to shared Library edgeXBuildGoApp with a few exceptions in default values of some parameters.

buildImage: false,\npushImage: false,\nsemverBump: 'pre'\n
Note: These parameters are not overridable.

"},{"location":"libraries/edgeXBuildGoMod/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoMod/#basic-example","title":"Basic example","text":"
edgeXBuildGoMod (\nproject: 'go-mod-configuration'\n)\n
"},{"location":"libraries/edgeXBuildGoMod/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoMod (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-go-project',\ndockerNexusRepo: 'staging',\nbuildImage: false,\npushImage: false,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\nbuildExperimentalDockerImage: false,\nartifactTypes: ['docker'],\nartifactRoot: 'archives/bin',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/","title":"edgeXBuildGoParallel","text":"

Shared Library to build Go projects and Docker images in parallel. Utilizes docker compose --parallel to build Docker images found in the workspace. Currently only used for the edgex-go mono-repo.

"},{"location":"libraries/edgeXBuildGoParallel/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildGoParallel/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build goVersion optional str The version of Go to use for building the project's CI build image. Note this parameter is used in conjuction with the useAlpineBase parameter to determine the base for the project's CI build image.Default: 1.20 goProxy optional str The proxy to use when downloading Go modules. The value of this parameter will be set in the GOPROXY environment variable to control the download source of Go modules.Default: https://nexus3.edgexfoundry.org/repository/go-proxy/ useAlpineBase optional bool Specify if an Alpine-based edgex-golang-base:${goVersion}-alpine image will be used as the base for the project's CI build image. If true, the respective edgex-golang-base image should exist in the Nexus snapshot repository, if a matching image is not found in Nexus then an Alpine-based go-lang:${goVersion}-alpine DockerHub image will be used. If false, then a non-Alpine go-lang:${goVersion} DockerHub image will be used. Note this parameter is used in conjuction with the goVersion parameter to determine the base for the projects' CI build image.Default: true dockerFileGlobPath optional str The pattern for finding Dockerfiles to build. Note Docker images will be named with the same name as the directory which the Dockerfile was found in with a docker- prefix and -go suffix. Example: docker-<folder>-goDefault: cmd/** /Dockerfile dockerImageNamePrefix optional str The prefix to apply to the names of all the Docker images built.Default: docker- dockerImageNameSuffix optional str The suffix to apply to the names of all the Docker images built.Default: -go dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker images will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to falseDefault: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false publishSwaggerDocs optional bool Specify if Jenkins should attempt to publish your projects API documentation to SwaggerHub. Note in order for Jenkins to publish to SwaggerHub you must ensure a valid value for swaggerApiFolders is set.Default: false swaggerApiFolders optional list The list of paths to your projects API Swagger-based documentation.Default: ['openapi/v1', 'openapi/v2'] failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildGoParallel/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoParallel/#basic-example","title":"Basic example","text":"
edgeXBuildGoParallel (\nproject: 'edgex-go',\ndockerFileGlobPath: 'cmd/** /Dockerfile',\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/#complex-example","title":"Complex example","text":"
edgeXBuildGoParallel(\nproject: 'edgex-go',\ndockerFileGlobPath: 'cmd/** /Dockerfile',\ntestScript: 'make test',\nbuildScript: 'make build',\npublishSwaggerDocs: true,\nswaggerApiFolders: ['openapi/v1', 'openapi/v2'],\nbuildSnap: true\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoParallel (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFileGlobPath: 'cmd/** /Dockerfile',\ndockerImageNamePrefix: 'docker-',\ndockerImageNameSuffix: '-go',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerNamespace: '',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1', 'openapi/v2'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXClair/","title":"edgeXClair","text":"

\u26a0\ufe0f Deprecated will be removed in a future version. DO NOT USE \u26a0\ufe0f

Shared library function to scan docker images for vulnerabilities using Klar. Please use edgeXSnyk instead.

"},{"location":"libraries/edgeXCodecov/","title":"edgeXCodecov","text":""},{"location":"libraries/edgeXCodecov/#overview","title":"Overview","text":"

Shared library to publish Codecov results to CodeCov.io

"},{"location":"libraries/edgeXCodecov/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value tokenFile false str Id of managed config file where token is stored. If null or empty, token file is automatically generated with: ${env.PROJECT}-codecov-token"},{"location":"libraries/edgeXCodecov/#usage","title":"Usage","text":"
edgeXCodecov('sample-service-codecov-token')\n
"},{"location":"libraries/edgeXDocker/","title":"edgeXDocker","text":""},{"location":"libraries/edgeXDocker/#overview","title":"Overview","text":"

Shared library that contains convenience functions for interacting with Docker. This shared library contains numerous functions so only a summary will be provided for each given function. If you have further questions about implementation details please refer to the source code.

"},{"location":"libraries/edgeXDocker/#functions","title":"Functions:","text":"
  • edgeXDocker.build: Build a docker image from optional baseImage with a set of default: docker build_args, labels, and tags.
  • edgeXDocker.buildInParallel: Build multiple docker images in parallel. This technique utilizes docker compose to build multiple images using the parallel flag.
  • edgeXDocker.generateDockerComposeForBuild: Supporting function for edgeXDocker.buildInParallel that generates a docker compose file for a given list of docker images.
  • edgeXDocker.generateServiceYaml: Supporting function for edgeXDocker.buildInParallel that generates service level yaml for a specific docker image.
  • edgeXDocker.push: Push a specific docker image and optionally tag it with the latest tag. A nexus repository can also optionally be specified as well as specific tags.
  • edgeXDocker.pushAll: Push all docker images specified in the dockerImages list. To be used in conjunction with the same input format used by edgeXDocker.buildInParallel to push all images.
  • edgeXDocker.getDockerTags: Generates the default set of tags used when pushing all edgex docker images with the edgeXDocker.push function.
  • edgeXDocker.finalImageName: Prepends a docker image with env.DOCKER_REGISTRY_NAMESPACE if defined.
  • edgeXDocker.cleanImageUrl: Returns image url without protocol.
  • edgeXDocker.parse: Reads a docker image url and returns the parsed image object components.
  • edgeXDocker.toImageStr: Returns docker image string from an image object.
"},{"location":"libraries/edgeXDocker/#parsed-image-object","title":"Parsed image object","text":"
[\nhost: hostname if any associated with the image,\nfullImage: full image name with tag,\nnamespace: namespace of the image if any,\nimage: image name without tag,\ntag: tag associated with the image if any\n]\n
"},{"location":"libraries/edgeXDockerLogin/","title":"edgeXDockerLogin","text":""},{"location":"libraries/edgeXDockerLogin/#overview","title":"Overview","text":"

Shared library that wraps the Linux Foundation's (LF) docker login script: ./resources/global-jjb/shell/docker-login.sh.

The LF Global JJB Docker Login script looks for the following environment variables: $SETTINGS_FILE, $DOCKER_REGISTRY, $REGISTRY_PORTS, $DOCKERHUB_REGISTRY, $DOCKERHUB_EMAIL which this script automatically sets. Based on given config map entries passed in

Please refer to the shell script in global-jjb/shell for the usage.

"},{"location":"libraries/edgeXDockerLogin/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value settingsFile true str Config file Id that contains authentication details to docker registries. Unique to each Edgex repository. dockerRegistry false str Override docker registry to login to. dockerRegistryPorts false str Listing of all the registry ports to login to e.g.: 10001 10002 10003 10004 dockerHubRegistry false str Override docker hub registry. Not commonly used. dockerHubEmail false str Override docker hub email. Not commonly used."},{"location":"libraries/edgeXDockerLogin/#usage","title":"Usage","text":"
edgeXDockerLogin(settingsFile: 'edgex-repo-settings')\n
"},{"location":"libraries/edgeXEmail/","title":"edgeXEmail","text":""},{"location":"libraries/edgeXEmail/#overview","title":"Overview","text":"

Shared library to send build success/fail emails generated by the edgexEmailUtil.generateEmailTemplate function.

"},{"location":"libraries/edgeXEmail/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value subject false str Email subject. Default: [${buildStatus}] ${env.JOB_NAME} Build #${env.BUILD_NUMBER} emailTo true str Comma separated list of email address(s) to send email to."},{"location":"libraries/edgeXEmail/#usage","title":"Usage","text":"
edgeXEmail(emailTo: 'bob@example.com,susan@example.com')\n
"},{"location":"libraries/edgeXEmailUtil/","title":"edgeXEmailUtil","text":""},{"location":"libraries/edgeXEmailUtil/#overview","title":"Overview","text":"

Shared library to support the edgeXEmail function by returning relevant build information that can be used to generate an email template. Email template can be found here: https://github.com/edgexfoundry/edgex-global-pipelines/tree/main/resources/email

"},{"location":"libraries/edgeXEmailUtil/#function-overview","title":"Function Overview","text":"
  • edgeXEmailUtil.getJobDetailsJson: Extract relevant build details including job information, author, git information, and failure log information and return map of details.
  • edgeXEmailUtil.generateEmailTemplate: Generate HTML email template from given job details usually generated by calling edgeXEmailUtil.getJobDetailsJson(). Email templates utilize mustache templates and leverage mustachejs for rendering.
"},{"location":"libraries/edgeXEmailUtil/#usage","title":"Usage","text":"
def jobDetails = edgeXEmailUtil.getJobDetailsJson()\ndef emailHtml  = edgeXEmailUtil.generateEmailTemplate(jobDetails)\n\n// do something with emailHtml...\n
"},{"location":"libraries/edgeXGHPagesPublish/","title":"edgeXGHPagesPublish","text":""},{"location":"libraries/edgeXGHPagesPublish/#overview","title":"Overview","text":"

Shared library to publish html and other resources to a GitHub pages branch off the main repository (typically gh-pages). This shared library is typically used in conjunction with mkdocs and after mkdocs generates all the HTML, etc and the calling pipeline stashes the contents into a specific site-contents Jenkins stash.

"},{"location":"libraries/edgeXGHPagesPublish/#process","title":"Process","text":"

The typical documentation build process goes like this:

  • PR is merged into main in upstream repo
  • mkdocs is called to generate final documentation in upstream repo job.
  • site-contents stash is generated in upstream repo job.
  • edgeXGHPagesPublish() is called to publish stash to GitHub pages.
"},{"location":"libraries/edgeXGHPagesPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value repoUrl true str Repo URL where GitHub pages are being published (typically in ssh format for Edgex). credentialId false str Jenkins credentialId used to authenticate to git to push contents. Default: edgex-jenkins-ssh ghPagesBranch false str Git branch where GitHub pages are stored. Default: gh-pages stashName false str Stash name that contains generated site contents that will be published. Default: site-contents"},{"location":"libraries/edgeXGHPagesPublish/#usage","title":"Usage","text":"
edgeXGHPagesPublish((repoUrl: 'git@github.com:edgexfoundry/edgex-docs.git')\n
"},{"location":"libraries/edgeXGeneric/","title":"edgeXGeneric","text":"

\u26a0\ufe0f Deprecated will be removed in a future version. DO NOT USE \u26a0\ufe0f

edgeXGeneric([\nproject: 'edgex-go',\nmavenSettings: ['edgex-go-codecov-token:CODECOV_TOKEN'], (optional)\ncredentials: [string(credentialsId: 'credential-id-here', variable: 'APIKEY')], (optional)\nenv: [\nGOPATH: '/opt/go-custom/go'\n],\npath: [\n'/opt/go-custom/go/bin'\n],\nbranches: [\n'*': [\npre_build: ['shell/install_custom_golang.sh'],\nbuild: [\n'make test raml_verify && make build docker',\n'shell/codecov-uploader.sh'\n]\n],\n'main': [\npost_build: [ 'shell/edgexfoundry-go-docker-push.sh' ]\n]\n]\n])\n
"},{"location":"libraries/edgeXInfraLFToolsSign/","title":"edgeXInfraLFToolsSign","text":""},{"location":"libraries/edgeXInfraLFToolsSign/#overview","title":"Overview","text":"

Shared library that wraps signing of git tags or files in a directory using lftools and Sigul. The signing is done inside a docker image managed by the EdgeX DevOps team.

Important: Signing git tags, requires the git tag to be an annotated tag. (git tag -a)

"},{"location":"libraries/edgeXInfraLFToolsSign/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value sigulConfig false str Config file Id that contains the Sigul config. Default: sigul-config sigulPassword false str Config file Id that contains the Sigul password. Default: sigul-password sigulPKI false str Config file Id that contains the Sigul PKI information. Default: sigul-pki lftoolsImageVersion false str DevOps managed lftools image version tag. Default: 0.23.1-centos7 command true str Command to run. Valid values: dir, git-tag directory true str Required if command is dir. version true str Required if command is git-tag. mode false str lftools sign mode. Default: parallel"},{"location":"libraries/edgeXInfraLFToolsSign/#usage","title":"Usage","text":"
edgeXInfraLFToolsSign(command: 'git-tag', version: 'v2.0.0')\n
edgeXInfraLFToolsSign([command: 'dir', directory: 'MyDirectory'])\n
"},{"location":"libraries/edgeXInfraPublish/","title":"edgeXInfraPublish","text":""},{"location":"libraries/edgeXInfraPublish/#overview","title":"Overview","text":"

Shared library used as a post build stage to publish build artifacts, logs, metrics to EdgeX Nexus server.

"},{"location":"libraries/edgeXInfraPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value logSettingsFile false str Config file id for settings to authenticate to Nexus to publish build logs. Default: jenkins-log-archives-settings dockerOptimized false str Whether or not to use a docker image when publishing to Nexus. Default: true"},{"location":"libraries/edgeXInfraPublish/#usage","title":"Usage","text":"
edgeXInfraPublish()\n
edgeXInfraPublish {\nlogSettingsFile = 'custom-jenkins-log-archives-settings'\ndockerOptimized = false\n}\n
"},{"location":"libraries/edgeXInfraShipLogs/","title":"edgeXInfraPublish","text":"

\u26a0\ufe0f Deprecated no longer in use. This has been replace by lfInfraShipLogs. DO NOT USE \u26a0\ufe0f

"},{"location":"libraries/edgeXLTS/","title":"edgeXLTS","text":""},{"location":"libraries/edgeXLTS/#overview","title":"Overview","text":"

Shared library with helper functions to manage LTS releases. Used as part of the edgeXRelease.groovy pipeline.

"},{"location":"libraries/edgeXLTS/#functions","title":"Functions:","text":"
  • edgeXLTS.prepLTS: Prepares a repository for an LTS release. If the repository is Golang based, go vendoring is enabled to support LTS releases.
  • edgeXLTS.getLatestLTSCommitId: Retrieves the latest LTS commit sha from a repository.
  • edgeXLTS.generateLTSCommitMessage: Creates a an LTS commit message for a release.
  • edgeXLTS.prepGoProject: Prepares a Golang based project for an LTS release enable vendoring and removing the vendor directory from the gitignore file.
"},{"location":"libraries/edgeXNexusPublish/","title":"edgeXNexusPublish","text":""},{"location":"libraries/edgeXNexusPublish/#overview","title":"Overview","text":"

Shared library to publish a ZIP file to a specific nexus repo.

"},{"location":"libraries/edgeXNexusPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value serverId true str Used to lookup credentials in mavenSettings file. Example: logs, docker, nexus.edgexfoundry.org mavenSettings true str Config file Id to use publish to Nexus. Example: log-settings nexusRepo true str The nexus repository name where you would like to publish your artifacts. nexusPath false str Path on the nexus server where file should be stored. Default:${env.SILO}/${env.JENKINS_HOSTNAME}/${env.JOB_NAME}/${env.BUILD_NUMBER} zipFilePath true str path to ZIP file, typically in the workspace."},{"location":"libraries/edgeXNexusPublish/#usage","title":"Usage","text":"
edgeXNexusPublish([serverId: 'logs', mavenSettings: 'log-settings', nexusRepo: 'logs', zipFilePath: '*.zip'])\n
"},{"location":"libraries/edgeXRelease/","title":"edgeXRelease","text":""},{"location":"libraries/edgeXRelease/#overview","title":"Overview","text":"

Shared library with helper functions to manage releases. This is the main entry point for all automated releases using the \ud83d\udd17 cd-management/release repository.

"},{"location":"libraries/edgeXRelease/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value name true str Name of the repository that is being released. version true str Semver version to be released. releaseName true str The codename of the release. This is usually used by sub release processes for naming. releaseStream true str What branch the release is being generated from. (This has been superseded by commitId) commitId true str Git Commit SHA to tag or branch for the release. repo true str https git repository url. Example: https://github.com/edgexfoundry/<repo>.git"},{"location":"libraries/edgeXRelease/#functions","title":"Functions","text":"
  • edgeXRelease.collectReleaseYamlFiles: Search through a provided file path and find all the release yaml files to process and parses yaml into a Groovy object using the readYaml function. Default file pattern to search for will be: release/*.yaml. This function will also validate what files have changed in the commit using edgex.didChange and will only release what was changed.
  • edgeXRelease.parallelStepFactory: Returns a Closure to execute the release for all release yaml entries found for the specific commit.
  • edgeXRelease.parallelStepFactoryTransform: Transforms release yaml Groovy object into a Groovy Closure containing all the logic needed to perform the release for the specific repository.
  • edgeXRelease.stageArtifact: If release contains binaries rather than docker images, the binaries need to be staged before the release occurs. This function forces a build of the artifact by triggering the job using the build(job: ..) Jenkins function.
  • edgeXRelease.getBuilderImagesFromReleasedImages: Used to determine what static builder image to use when building a LTS C based repository. Below you can see the transformation.
     // Given the release of the following 2 docker images:\nedgeXRelease.getBuilderImagesFromReleasedImages('nexus3.edgexfoundry.org:10004/sample-service-c')\n> nexus3.edgexfoundry.org:10002/sample-service-c-builder-x86_64:jakarta\n\n edgeXRelease.getBuilderImagesFromReleasedImages('nexus3.edgexfoundry.org:10004/sample-service-c-arm64')\n> nexus3.edgexfoundry.org:10002/sample-service-c-builder-arm64:jakarta\n
"},{"location":"libraries/edgeXReleaseDockerImage/","title":"edgeXReleaseDockerImage","text":""},{"location":"libraries/edgeXReleaseDockerImage/#overview","title":"Overview","text":"

Shared library with helper functions to manage docker image releases to Nexus release and DockerHub.

"},{"location":"libraries/edgeXReleaseDockerImage/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value dockerImage true str Determines whether or not to trigger this function. docker true array Array of docker images to release. docker.image true str Docker image that is being release. docker.destination true array Array of destination registries where to release the image to."},{"location":"libraries/edgeXReleaseDockerImage/#functions","title":"Functions","text":"
  • edgeXReleaseDockerImage.getAvaliableTargets: Returns a list of valid release registries.
  • edgeXReleaseDockerImage.isValidReleaseRegistry: Validates registry to ensure we are not pushing images to unknown registries.
  • edgeXReleaseDockerImage.publishDockerImages: Iterates through all release registry targets and pushes images based on validating image exists.
  • edgeXReleaseDockerImage.publishDockerImage: Pulls, re-tags and pushes source image to destination registry.
  • edgeXReleaseDockerImage.validate: Validates release yaml input before any automation is run.
  • edgeXReleaseDockerImage.imageExists: Checks docker registry to see if image exists.
"},{"location":"libraries/edgeXReleaseDockerImage/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseDockerImage/#sample-release-yaml","title":"Sample Release Yaml","text":"
version: 1.1.2\nreleaseStream: main\ndockerImage: true\ndocker:\n- image: nexus3.edgexfoundry.org:10004/sample-service\ndestination:\n- nexus3.edgexfoundry.org:10002/sample-service\n- docker.io/edgexfoundry/sample-service\n- image: nexus3.edgexfoundry.org:10004/sample-service-arm64\ndestination:\n- nexus3.edgexfoundry.org:10002/sample-service-arm64\n- docker.io/edgexfoundry/sample-service-arm64\n
"},{"location":"libraries/edgeXReleaseDockerImage/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseDockerImage(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseDocs/","title":"edgeXReleaseDocs","text":""},{"location":"libraries/edgeXReleaseDocs/#overview","title":"Overview","text":"

Shared library with helper functions to manage documentation releases. Currently used by edgex-docs.

"},{"location":"libraries/edgeXReleaseDocs/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value docs true str Determines whether or not to trigger this function. docsInfo.nextReleaseVersion true str Next release version to add to the documentation. docsInfo.nextReleaseName true str Next release name to add to the documentation. docsInfo.reviewers true str Who to assign the generated PR's to."},{"location":"libraries/edgeXReleaseDocs/#functions","title":"Functions","text":"
  • edgeXReleaseDocs.publishReleaseBranch: Makes release branch related changes in unique branch then commits release branch.
  • edgeXReleaseDocs.publishVersionChangesPR: Makes version file related changes in unique branch then commits and opens PR.
  • edgeXReleaseDocs.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseDocs/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseDocs/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'edgex-docs'\nversion: '2.2.0'\nreleaseName: 'kamakura'\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/edgex-docs.git'\ncommitId: 'c72b16708d6eed9a08be464a432ce22db7d90667'\ngitTag: false\ndockerImages: false\ndocs: true\ndocsInfo:\nnextReleaseVersion: \"2.3.0\"\nnextReleaseName: levski\nreviewers: edgex-docs-committers\n
"},{"location":"libraries/edgeXReleaseDocs/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseDocs(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitHubAssets/","title":"edgeXReleaseGitHubAssets","text":""},{"location":"libraries/edgeXReleaseGitHubAssets/#overview","title":"Overview","text":"

Shared library with helper functions to manage GitHub Releases with attached binaries. This function works in conjunction with the docker image generated from \ud83d\udd17 Create GitHub Release to manage GitHub releases. Currently used by edgex-cli.

"},{"location":"libraries/edgeXReleaseGitHubAssets/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value gitHubRelease true str Determines whether or not to trigger this function. gitHubReleaseAssets true array List of binaries to release along with generated GitHub Release."},{"location":"libraries/edgeXReleaseGitHubAssets/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubAssets.getCredentialsId: Return correct PAT based on ENV.SILO to access GitHub api.
  • edgeXReleaseGitHubAssets.getRepoInfo: Extracts pertinent information from repository and returns as Map.
  • edgeXReleaseGitHubAssets.createGitHubRelease: Wraps call to create-github-release to generate GitHub release.
  • edgeXReleaseGitHubAssets.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseGitHubAssets/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseGitHubAssets/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'sample-service'\nversion: 1.1.2\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/sample-service.git'\ngitHubRelease: true\ngitHubReleaseAssets:\n- 'https://nexus-location/asset1'\n- 'https://nexus-location/asset2'\n- 'https://nexus-location/asset3'\n
"},{"location":"libraries/edgeXReleaseGitHubAssets/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseGitHubAssets(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitTag/","title":"edgeXReleaseGitHubTag","text":""},{"location":"libraries/edgeXReleaseGitTag/#overview","title":"Overview","text":"

Shared library with helper functions to create, sign and bump Git tags.

"},{"location":"libraries/edgeXReleaseGitTag/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value gitTag true str Determines whether or not to trigger this function. semverBumpLevel false str Semver bump level to be used by git-semver. Default: -pre=dev pre"},{"location":"libraries/edgeXReleaseGitTag/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubTag.cloneRepo: Generic function to properly clone a repository to a specific subfolder. Directory name generated from releaseYaml.name.
  • edgeXReleaseGitHubTag.setAndSignGitTag: Sets up release tag using git-semver from the specified version set in releaseYaml.version. NOTE: git-semver force is used here for impotency in case tag already exists. So existing tags will be overridden.
  • edgeXReleaseGitHubTag.bumpAndPushGitTag: Pushes signed tag and optionally bumps next version.
"},{"location":"libraries/edgeXReleaseGitTag/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseGitTag/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'sample-service'\nversion: '1.1.2'\nreleaseStream: 'main'\ncommitId: '0cc1d67607642c9413e4a80d25a2df35ecc76d41'\nrepo: 'https://github.com/edgexfoundry/sample-service.git'\ngitTag: true\nsemverBumpLevel: 'patch' #optional\n
"},{"location":"libraries/edgeXReleaseGitTag/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseGitTag(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitTagUtil/","title":"edgeXReleaseGitHubTagUtil","text":""},{"location":"libraries/edgeXReleaseGitTagUtil/#overview","title":"Overview","text":"

Shared library with supporting helper functions to manage Git tags.

"},{"location":"libraries/edgeXReleaseGitTagUtil/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubTagUtil.getSSHRepoName: Converts https repo remote to ssh git@github.com: remote.
  • edgeXReleaseGitHubTagUtil.signGitTag: Wrapper around edgeXInfraLFToolsSign that signs git tag for a release.
  • edgeXReleaseGitHubTagUtil.releaseGitTag: Main function that does full end-to-end git tag release.
  • edgeXReleaseGitHubTagUtil.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseOpenApi/","title":"edgeXReleaseOpenApi","text":""},{"location":"libraries/edgeXReleaseOpenApi/#overview","title":"Overview","text":"

Shared library with helper functions to manage OpenAPI YAML related changes. Currently used by sdk repos.

"},{"location":"libraries/edgeXReleaseOpenApi/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value apiInfo.nextReleaseVersion true str Next release version to for the OpenAPI yaml files. apiInfo.reviewers true str Who to assign the generated PR to."},{"location":"libraries/edgeXReleaseOpenApi/#functions","title":"Functions","text":"
  • edgeXReleaseOpenApi.publishReleaseBranch: Makes release branch related changes in unique branch then commits release branch.
  • edgeXReleaseOpenApi.publishOpenApiChanges: Makes OpenAPI related changes in unique branch then commits and opens PR.
  • edgeXReleaseOpenApi.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseOpenApi/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseOpenApi/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'device-sdk-go'\nversion: '2.2.0'\nreleaseName: 'kamakura'\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/device-sdk-go.git'\ncommitId: 'c72b16708d6eed9a08be464a432ce22db7d90667'\ngitTag: true\ndockerImages: false\ngitHubRelease: false\napiInfo: [\nnextReleaseVersion: '2.3.0',\nreviewers: edgexfoundry/edgex-committers\n]\n
"},{"location":"libraries/edgeXReleaseOpenApi/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseOpenApi(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseSnap/","title":"edgeXReleaseSnap","text":"

\u26a0\ufe0f Deprecated... Snaps are no longer published by EdgeX DevOps. They are now managed by the team at Canonical. DO NOT USE \u26a0\ufe0f

"},{"location":"libraries/edgeXSemver/","title":"edgeXSemver","text":""},{"location":"libraries/edgeXSemver/#overview","title":"Overview","text":"

Shared library containing a useful set of functions to help with the creation of semantic versioning using the git-semver python library. The main call function builds the git semver command based on the provided input.

Please note: this shared library is responsible for setting the VERSION environment variable during git semver init execution.

"},{"location":"libraries/edgeXSemver/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value command false str Specify which git semver sub command to run. Example: init, bump, push semverVersion false string Force a specific override version instead of reading the version from the semver branch. Default: <empty string> gitSemverVersion false string What version of the git-semver docker image to use. Default: latest credentials false string Which Jenkins credential to use to authenticate to GitHub and push git tag. Default: edgex-jenkins-ssh"},{"location":"libraries/edgeXSemver/#functions","title":"Functions","text":"
  • edgeXSemver.executeGitSemver: Execute semverCommand via ssh with provided credentials.
  • edgeXSemver.setGitSemverHeadTag: set GITSEMVER_HEAD_TAG to value of HEAD when any of the following conditions are satisfied:
  • An init version is specified and HEAD is tagged with init version.
  • An init version is not specified and HEAD is tagged.
  • edgeXSemver.getCommitTags: Return list of all tags at a specific commit point.
"},{"location":"libraries/edgeXSemver/#usage","title":"Usage","text":"

Regular init

edgeXSemver('init')\n

Force specific the semver version to use.

edgeXSemver('init', '2.0.0')\n

Bump the semver version using default semver bump level (pre-release).

edgeXSemver('bump')\n
"},{"location":"libraries/edgeXSetupEnvironment/","title":"edgeXSetupEnvironment","text":""},{"location":"libraries/edgeXSetupEnvironment/#overview","title":"Overview","text":"

Shared library to setup a build environment given a Map of key value pairs. Some extra environment variables are set to help with the build process including:

  • GIT_BRANCH
  • GIT_COMMIT
  • GIT_BRANCH_CLEAN
  • SHORT_GIT_COMMIT
  • SEMVER_BRANCH
  • SEMVER_PRE_PREFIX
"},{"location":"libraries/edgeXSetupEnvironment/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value vars false str A Map of key/value pairs to expose to the Jenkins environment."},{"location":"libraries/edgeXSetupEnvironment/#usage","title":"Usage","text":"
edgeXSetupEnvironment([ PROJECT: 'edgex-global-pipelines' ])\n...\n...\n// This will expose an environment variable named `PROJECT` with the value `edgex-global-pipelines`\n// as well as the extra environment vars mentioned above.\n
"},{"location":"libraries/edgeXSnap/","title":"edgeXSnap","text":""},{"location":"libraries/edgeXSnap/#overview","title":"Overview","text":"

\u26a0\ufe0f Deprecated Warning... Snaps are no longer being built as part of the Jenkins pipeline. They are being built and tested using GitHub Actions and are managed by the team at Canonical. DO NOT USE \u26a0\ufe0f

Wrapper around resources/snap-build.sh script. No parameters required.

"},{"location":"libraries/edgeXSnap/#usage","title":"Usage","text":"
edgeXSnap()\n
"},{"location":"libraries/edgeXSnyk/","title":"edgeXSnyk","text":""},{"location":"libraries/edgeXSnyk/#overview","title":"Overview","text":"

Shared library containing a useful set of functions to help with the creation of semantic versioning using the git-semver python library. The main call function builds the git semver command based on the provided input.

Please note: this shared library is responsible for setting the VERSION environment variable during git semver init execution.

"},{"location":"libraries/edgeXSnyk/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value command false str Specify which Snyk command to run. Possible values: test, monitor. Default: monitor dockerImage false string If scanning a docker image either a local image name or remote image name. dockerFile false string If scanning a docker image, the path to Dockerfile relative to the Jenkins WORKSPACE. severity false string Severity threshold to mark the build as unstable. sendEmail false string Whether or not to send an email of the findings. Default: true emailTo false string Recipient list of who to send the email to. htmlReport false string Whether or not to generate an HTML report of findings. Default: false"},{"location":"libraries/edgeXSnyk/#usage","title":"Usage","text":"

Test and continuously monitor project dependencies. For Go projects, this is typically the go.mod file:

edgeXSnyk()\n

Test docker image for vulnerabilities and output results to Jenkins console:

edgeXSnyk(\ncommand: 'test',\ndockerImage: 'nexus3.edgexfoundry.org:10004/core-command:latest',\ndockerFile: '<path to Dockerfile>'\n)\n

Test docker image for vulnerabilities and send email of findings:

edgeXSnyk(\ncommand: 'test',\ndockerImage: 'nexus3.edgexfoundry.org:10004/core-command:latest',\ndockerFile: '<path to Dockerfile>',\nseverity: 'high',\nsendEmail: true,\nemailTo: <email address(s)>,\nhtmlReport: true\n)\n
"},{"location":"libraries/edgeXSwaggerPublish/","title":"edgeXSwaggerPublish","text":""},{"location":"libraries/edgeXSwaggerPublish/#overview","title":"Overview","text":"

Shared library containing methods to publish Swagger API docs up to https://api.swaggerhub.com.

NOTE: ${APIKEY} needs to be a pointer to a file with the key. This will need to be set locally from your environment or from Jenkins.

"},{"location":"libraries/edgeXSwaggerPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value owner false str Specify Swagger API owner. Default: EdgeXFoundry1 apiFolders true string Space delimited list of folders to publish. swaggerCredentialId false string Config file Id that contains the Swagger API key to allow publishing of API docs. Default: swaggerhub-api-key"},{"location":"libraries/edgeXSwaggerPublish/#usage","title":"Usage","text":"

Publish single folder to Swagger to owner:EdgeXFoundry1

edgeXSwaggerPublish(apiFolders: 'openapi/v1')\n

Publish multiple API folders to Swagger to owner:EdgeXFoundry1

edgeXSwaggerPublish(apiFolders: 'openapi/v1 openapi/v2')\n

Publish single folder to swagger with a customer owner/organization.

edgeXSwaggerPublish(owner: 'customOwner', apiFolders:'openapi/v1')\n
"},{"location":"libraries/edgeXUpdateNamedTag/","title":"edgeXUpdateNamedTag","text":""},{"location":"libraries/edgeXUpdateNamedTag/#overview","title":"Overview","text":"

Shared library that wraps the resources/update-named-tag.sh script. This script will create a new \"named\" git tag pointing to an existing git tag. This is really useful for creating \"stable\" or \"experimental\" tags that point to another specific versioned git tag. For example, if you wanted to have a \"stable\" tag point to a version tag of \"v1.4.0\" you can run this script to do so. See usage below.

"},{"location":"libraries/edgeXUpdateNamedTag/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value ogVersion true str Original version to create named tag from. namedVersion true str Space delimited list of folders to publish."},{"location":"libraries/edgeXUpdateNamedTag/#usage","title":"Usage","text":"

Create a stable tag pointing to a specific version.

edgeXUpdateNamedTag('v1.2.3', 'stable')\n

Create an experimental tag pointing to a specific version.

edgeXUpdateNamedTag('v2.1.20', 'experimental')\n
"},{"location":"libraries/edgex/","title":"edgex","text":""},{"location":"libraries/edgex/#overview","title":"Overview","text":"

Shared library of common helper functions for all EdgeX Jenkins pipelines.

"},{"location":"libraries/edgex/#functions","title":"Functions","text":"
  • edgex.isReleaseStream: Used to validate whether the current branch that Jenkins is building is a branch that is considered a branch with \"releasable\" artifacts (i.e docker push, git semver push).
  • edgex.isLTS: Used to determine if the current branch that Jenkins is building is for an LTS release.
  • edgex.getTargetBranch: Used to determine the target branch that is being merged into for a PR.
  • edgex.didChange: Determine if the given expression matches the files that changed in a given PR or merge. For example:
    // Did any .go files change from the current branch compared to origin/main\ndidChange('*.go')\n\n// Did any .yaml files change from the current branch compared to origin/release\ndidChange('*.yaml', 'origin/release')\n
  • edgex.mainNode: Given a config map with config.nodes, either return the node label marked as defaultNode = true or return the DevOps managed \"default\" node label.
  • edgex.nodeExists: Verify a given node architecture matches provided architecture.
  • edgex.getNode: Return node with architecture that matches provided architecture.
  • edgex.setupNodes: Setup default node labels for x86_64 and arm64 nodes.
  • edgex.getVmArch: Run uname to determine VM architecture. If aarch64 is returned, convert to the result to arm64.
  • edgex.bannerMessage: Vanity function to wrap given input message with a banner style output for easier readability in Jenkins console.
  • edgex.printMap: Vanity function to print Groovy Map to the Jenkins console.
  • edgex.defaultTrue: Returns true if the input is true or null. This is useful to setup default values in functions when none is provided.
  • edgex.defaultFalse: Returns true if the input is false or null. This is useful to setup default values in functions when none is provided.
  • edgex.releaseInfo: Call shell script resources/releaseinfo.sh to output current edgex-global-pipeline version information in the Jenkins console. This is really useful for debugging older builds in case issues are discovered.
  • edgex.isDryRun: Whether or not the env.DRY_RUN environment variable is set. Will return true if DRY_RUN is set, false otherwise.
  • edgex.isMergeCommit: Determines if the current commit Jenkins is building is considered a git \"merge commit\". Useful if determining parent commit info.
  • edgex.getPreviousCommit: Determines the previous commit SHA given the merge commit or squash commit git use-cases. Different git commands have to be run to be able to determine the previous commit.
  • edgex.getBranchName: Returns the current branch name from git.
  • edgex.getCommitMessage: Returns the current commit message from git given a commit SHA.
  • edgex.isBuildCommit: Return true when the commit message follows the pattern build(...): [semanticVersion,namedTag] ....
  • edgex.parseBuildCommit: Return the parameters for the build [semanticVersion,namedTag].
  • edgex.getTmpDir: Run mktemp with given pattern to create a temporary directory in /tmp.
  • edgex.getGoLangBaseImage: Return DevOps managed base images used in Go pipelines.
  • edgex.isGoProject: Looks at repository directory structure to determine if the repository is Golang based. Uses the existence of the go.mod file.
  • edgex.getCBaseImage: Return the base image used as the base image for all C based repositories.
  • edgex.parallelJobCost: Wraps call to lfParallelCostCapture inside docker image to save time downloading pip dependencies.
  • edgex.patchAlpineSeccompArm64: A fix for arm64 nodes that enables a security profile for docker. Another workaround is to just use the --privileged docker flag.
  • edgex.isLTSReleaseBuild: Returns true if current commit message begins with ci(lts-release).
  • edgex.semverPrep: Poorly named function that sets up the env.NAMED_TAG and env.BUILD_STABLE_DOCKER_IMAGE for the build commit concept. Will be removed in a future release.
  • edgex.waitFor: Useful function to wait for a condition in a shell script to be met.
  • edgex.waitForImages: Useful function to determine if a docker image has been pushed to a repository.
  • edgex.commitChange: Commits a change to the repo with a given message.
  • edgex.createPR: Creates a PR with the GitHub CLI for with a given branch, title, message and reviewers for. Note: This is generic enough to be used in other functions.
"},{"location":"releases/jakarta-lts-initial/","title":"Jakarta LTS Changes","text":""},{"location":"releases/jakarta-lts-initial/#cd-management","title":"cd-management","text":"
  • New release branch in cd-management to manage lts. Maybe call it lts
  • New field in YAML signifying that this is an LTS release:
---\nname: 'edgex-go'\nversion: '2.1.0'\nreleaseName: 'jakarta'\nreleaseStream: 'main'\nlts: true # <-- new field\n...\n
"},{"location":"releases/jakarta-lts-initial/#questions","title":"Questions?","text":"
  • Should we name the lts branch for all repos lts? OR use it's codename like jakarta?

This would trigger a new process in edgex-global-pipelines@edgeXRelease. See changes to edgex-global-pipelines

"},{"location":"releases/jakarta-lts-initial/#ci-build-images","title":"ci-build-images","text":"
  • Branch the golang-1.16 branch to golang-1.16-lts or similar and push the resulting image to the Nexus release repo.
  • Branch the gcc branch to gcc-lts or similar and push the resulting image to the Nexus release repo.

These images should be pretty simple as to push to Nexus release because edgeXBuildDocker allows us to specify the Nexus release repository as a target. See dockerNexusRepo in the docs.

"},{"location":"releases/jakarta-lts-initial/#edgex-compose","title":"edgex-compose","text":"

3rd party docker images should be archive to the Nexus release repository. Images that should be archived are:

consul kong lfedge/ekuiper postgres redis vault

A modification to the Jenkinsfile can be make to introduce a new pipeline parameter to trigger a stage that gathers the existing 3rd party images, retags and pushes them to the Nexus release repository.

Sample script to extract and retag:

for image in $(grep \"image:\" ./docker-compose.yml | grep -v nexus | awk '{print $2}' | sort); do echo docker tag $image nexus3.edgexfoundry.org:10002/3rdparty/$image; echo docker push nexus3.edgexfoundry.org:10002/3rdparty/$image; done\n
"},{"location":"releases/jakarta-lts-initial/#edgex-global-pipelinesedgexrelease","title":"edgex-global-pipelines@edgeXRelease","text":"

Various changes will be needed in vars/edgexRelease.groovy to support the lts release. See https://github.com/edgexfoundry/edgex-global-pipelines/blob/main/vars/edgeXRelease.groovy#L38. If we are doing an LTS release we should not create a tag, we need to create a long running branch where changes can be made without affecting the main branch.

"},{"location":"releases/jakarta-lts-initial/#changes-for-go-repositories","title":"Changes For Go Repositories","text":"

As called out in the LTS release process, for Go based projects, we will switch to Go vendoring for dependencies. This will give us 100% confidence that the dependencies will always be available in the LTS release and allow for easy patching and rebuilding.

  • If the release is an LTS release and the LTS branch does not exist, we will need to run something similar to the following:
git checkout -b <lts-release-name>\ngrep -v vendor .gitignore > .gitignore.tmp\nmv .gitignore.tmp .gitignore\nmake vendor\ngit add .\ngit commit -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
  • If the release is an LTS release and the LTS branch does exist, we will need to run something similar to the following:
git checkout <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
"},{"location":"releases/jakarta-lts-initial/#changes-for-c-repositories","title":"Changes For C Repositories","text":"

There is no dependency management for C based projects, so no dependency management changes are needed. We will need to branch and push though.

  • If the release is an LTS release and the LTS branch does not exist, we will need to run something similar to the following:
git checkout -b <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
  • If the release is an LTS release and the LTS branch does exist, we will need to run something similar to the following:
git checkout <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
"},{"location":"releases/jakarta-lts-initial/#edgex-global-pipelines-general-changes","title":"edgex-global-pipelines General Changes","text":""},{"location":"releases/jakarta-lts-initial/#semver-notes-and-noop-builds","title":"Semver notes and noop builds","text":"
  • Git semver will continue to be used for lts releases. After the initial release a pre-release dev tag will be created as usual. However, we have to introduce the concept of a noop (no operation) build due to the fact we are branching and tagging. We can use the commit message as a way to determine a noop build. The flow will go something like this:

    1. 1st build, triggered by push of lts branch to GitHub: No op, no semver needed
    2. edgeXRelease creates force creates tag 2.1.0
    3. 2nd build, triggered by edgeXRelease and builds the 2.1.0 code and pushes the release to Nexus
    4. Bump semver to 2.1.1-dev.1
  • vars/edgex.groovy

  • Potentially need to add a new method similar to isReleaseStream() called isLTS().
  • Add method or modify getGoLangBaseImage() to return the proper released ci-build-image if this is an LTS release
  • vars/edgeXBuildGoApp.groovy
  • For LTS releases we need to use the released CI base build image referenced in the ci-build-images section. So we will need to modify this method prepBaseBuildImage() to return the proper base build image if the release is an LTS release. Will call edgex function above.
  • vars/edgeXBuildGoParallel.groovy
  • For LTS releases we need to use the released CI base build image referenced in the ci-build-images section. So we will need to modify this method prepBaseBuildImage() to return the proper base build image if the release is an LTS release. Will call edgex function above.
  • vars/edgeXBuildCApp.groovy
  • This will be the most complicated change. We will need to release/archive the build images created from the Dockerfile.build. These images will need to be pushed to nexus release and then used as the base images for all subsequent LTS builds. This will ensure we have 100% reproducibility of the C repositories. For example we will need to create a device-coap-c specific docker image will all build dependencies archived in the image.
  • A new stage will need to be added to the pipeline to release the docker build images. This stage can either be triggered by a new parameter to the pipeline, or can potentially be triggered by a special commit message. Since we are already doing a special commit message for the initial push, the commit message may be the correct approach.
  • Changes will be required to the prepBaseBuildImage() function, to use repo level build images if we are on an LTS branch.
"},{"location":"releases/jakarta-release-stages/","title":"Jakarta Release Stages","text":""},{"location":"releases/jakarta-release-stages/#release-architecture","title":"Release Architecture","text":""},{"location":"releases/jakarta-release-stages/#pre-lts-flow","title":"Pre-LTS Flow","text":""},{"location":"releases/jakarta-release-stages/#post-lts-flow","title":"Post-LTS Flow","text":""},{"location":"releases/jakarta-release-stages/#c-based-services","title":"C Based Services","text":""},{"location":"releases/jakarta-release-stages/#release-flow","title":"Release Flow","text":"
  • \ud83c\udd95 edgeXRelease: creates and pushes \"jakarta\" branch at specific git sha
  • The push of the tag triggers new LTSRelease build
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/lts-test/19/pipeline/81
  • \"LTS Release Build\", builds project specific relevant ci build images (x86_64, arm64) will all dependencies bundled
  • Images are pushed to nexus release, i.e. nexus3.edgexfoundry.org:10002/device-coap-c-builder-{ARCH}:{GIT SHA}
  • [Existing] edgeXRelease: tags git sha with release version e.g. 2.1.0
  • [Existing] edgeXRelease: stages build artifact, i.e. triggers device-coap-c/jakarta job
  • \ud83c\udd95 If this is a C build and LTS we will need to wait until the first LTSRelease build is done before running this build. New function edgex.waitForImages is used to wait until builder images are ready.
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/lts-test/20/pipeline/154
  • [Existing] edgeXRelease: Bump Semver, i.e. next dev tag 2.1.1-dev.1
"},{"location":"releases/jakarta-release-stages/#pr-fixes-regular-dev-process","title":"PR Fixes (Regular Dev Process)","text":"

PR is open in fork as normal, but target branch will be LTS (jakarta) branch

  • [Existing] User open's PR as normal for fix, etc https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/PR-27/7/pipeline/213
  • \ud83c\udd95 Pipeline will detect the merge target is an LTS branch and will use released ci build image from the release process rather than build a ci image on the fly
  • prepBaseBuildImage() was the perfect abstraction to do this!

    docker pull nexus3.edgexfoundry.org:10002/device-coap-c-builder-x86_64:{GIT SHA}\ndocker tag nexus3.edgexfoundry.org:10002/device-coap-c-builder-x86_64:{GIT SHA} ci-base-image-x86_64\n
    docker pull nexus3.edgexfoundry.org:10002/device-coap-c-builder-arm64:{GIT SHA}\ndocker tag nexus3.edgexfoundry.org:10002/device-coap-c-builder-arm64:{GIT SHA} ci-base-image-arm64\n
"},{"location":"releases/jakarta-release-stages/#main-branch-regular-dev-process","title":"Main Branch (Regular Dev Process)","text":"

PR open against the main branch, no regressions introduced: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/PR-29/2/pipeline

"},{"location":"releases/jakarta-release-stages/#go-based-services","title":"Go based services","text":""},{"location":"releases/jakarta-release-stages/#release-flow_1","title":"Release Flow","text":"
  • \ud83c\udd95 edgeXRelease: creates and pushes \"jakarta\" branch at specific git sha
  • The push of the tag triggers new LTSRelease build
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/lts-test/24/pipeline
  • \"LTS Release Build\" will be a no op build in the case of Golang
  • [Existing] edgeXRelease: tags git sha with release version e.g. 2.1.0
  • [Existing] edgeXRelease: stages build artifact, i.e. triggers sample-service/jakarta job
  • \ud83c\udd95 No wait needed as of yet, but maybe will need something in the future
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/lts-test/25/pipeline/147 (need to add lts branches to isReleaseStream)
  • [Existing] edgeXRelease: Bump Semver, i.e. next dev tag 2.1.1-dev.1
"},{"location":"releases/jakarta-release-stages/#pr-fixes-regular-dev-process_1","title":"PR Fixes (Regular Dev Process)","text":"

PR is open in fork as normal, but target branch will be LTS (jakarta) branch

  • [Existing] User open's PR as normal for fix, etc https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/PR-135/9/pipeline
  • \ud83c\udd95 getGolangBaseImage will return Go LTS image that DevOps manually releases into Nexus release

    docker build -t ci-base-image-x86_64 -f Dockerfile --build-arg BASE=nexus3.edgexfoundry.org:10002/edgex-devops/edgex-golang-base:1.16-alpine-lts --build-arg 'MAKE=echo noop' --target=builder .\n
    docker build -t ci-base-image-arm64 -f Dockerfile --build-arg BASE=nexus3.edgexfoundry.org:10002/edgex-devops/edgex-golang-base-arm64:1.16-alpine-lts --build-arg MAKE=\"echo noop\" --target=builder .\n
"},{"location":"releases/jakarta-release-stages/#main-branch-regular-dev-process_1","title":"Main branch (Regular Dev Process)","text":"

PR open against the main branch, no regressions introduced: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/PR-136/1/pipeline

"},{"location":"tutorials/","title":"Tutorials","text":"

More coming soon!

  • Manual Version Bump
  • Pull Request Sandbox Testing
"},{"location":"tutorials/docker-build-strategy/","title":"Docker Build Strategy","text":"

Docker is a great tool for the CI/CD ecosystem. As the EdgeX DevOps community, we made the decision early when designing the EdgeX Jenkins pipelines to make Docker the center of our build strategy. The advantage of using Docker as the build context is that it allows for creating reproducible builds from Jenkins to our local build environment. Thus creating a portable build environment and minimizing build errors between environments. The EdgeX Jenkins pipelines use Docker images as the context for any build. This Docker image is generated from the Dockerfile.build found at the root of every EdgeX repository. Any dependencies or packages required for testing or compilation needs to be added to the Dockerfile.build file.

"},{"location":"tutorials/docker-build-strategy/#local-testing","title":"Local Testing","text":"

If we want to test how the build will run on Jenkins we can follow these steps locally.

"},{"location":"tutorials/docker-build-strategy/#example","title":"Example","text":"

First we build the \"build image\" edgex-ci-build-image

cd app-service-configurable\ndocker build -t edgex-ci-build-image -f Dockerfile.build\n

Now we run the build image with some make targets and bind mount our current directory to a folder called /ws (workspace)

docker run --rm -v $(pwd):/ws -w /ws edgex-ci-build-image sh -c 'make test build'\n

Or to put it into a convenient one-liner:

cd app-service-configurable\ndocker build -t edgex-ci-build-image -f Dockerfile.build . && docker run --rm -v $(pwd):/ws -w /ws edgex-ci-build-image sh -c 'make test build'\n
Sending build context to Docker daemon    127kB\nStep 1/8 : ARG BASE=golang:1.15-alpine\nStep 2/8 : FROM ${BASE}\n ---> 1a87ceb1ace5\nStep 3/8 : LABEL license='SPDX-License-Identifier: Apache-2.0'   copyright='Copyright (c) 2019: Intel'\n ---> Using cache\n ---> 9f1aa172c1d7\nStep 4/8 : RUN sed -e 's/dl-cdn[.]alpinelinux.org/nl.alpinelinux.org/g' -i~ /etc/apk/repositories\n ---> Using cache\n ---> fec4da09e9ec\nStep 5/8 : RUN apk add --no-cache make git gcc libc-dev libsodium-dev zeromq-dev bash\n...\nSuccessfully built ce2be0b9fe31\nSuccessfully tagged edgex-ci-build-image:latest\nCGO_ENABLED=1 go test -coverprofile=coverage.out ./...\n?   github.com/edgexfoundry/app-service-configurable\n    [no test files]\nCGO_ENABLED=1 go build -ldflags \"-X github.com/edgexfoundry/app-functions-sdk-go/internal.SDKVersion=v1.2.1-dev.35 -X github.com/edgexfoundry/app-functions-sdk-go/internal.ApplicationVersion=0.0.0\" app-service-configurable\n
"},{"location":"tutorials/docker-build-strategy/#tooling-caveats","title":"Tooling Caveats","text":"

Docker build images are Alpine based to save on disk space and bandwith and with that comes potential tooling incompatiblities. For example a number of pre-installed base packages on Alpine are the BusyBox versions of the tools. BusyBox versions can sometimes have different arguments than their GNU counterparts. For instance the tar command:

"},{"location":"tutorials/docker-build-strategy/#busybox-alpine","title":"BusyBox (Alpine)","text":"
$ tar --help\nBusyBox v1.31.1 () multi-call binary.\n\nUsage: tar c|x|t [-ZzJjahmvokO] [-f TARFILE] [-C DIR] [-T FILE] [-X FILE] [--exclude PATTERN]... [FILE]...\n
"},{"location":"tutorials/docker-build-strategy/#gnu-other-linux-distros","title":"GNU (Other linux distros)","text":"
$ tar --help\nUsage: tar [OPTION...] [FILE]...\nGNU 'tar' saves many files together into a single tape or disk archive, and can\nrestore individual files from the archive.\n

This can lead to unexpected issues if say, for instance, you are depending on a specific flag provided by the tool. One option to fix this is to just use the BusyBox flags, however this may break when not running inside the Docker build image. Another option is to find the alternative package and install that version. For example, Alpine provides the GNU alternative tar binary under the tar Alpine package:

$ apk add --update tar\n$ tar --help\nUsage: tar [OPTION...] [FILE]...\nGNU 'tar' saves many files together into a single tape or disk archive, and can\nrestore individual files from the archive.\n
"},{"location":"tutorials/docker-build-strategy/#the-jenkins-way","title":"The Jenkins Way","text":"

The above example is similar to how Jenkins runs the build with a few distinctions. First, the make test and make build commands are broken up into two stages. This is an important distinction because it allows for a more granular pipeline allowing for better error handling. The other distinction is that Jenkins takes advantage of a caching base layer image that is passed in at build time. Take a look at the Dockerfile.build. You will notice the BASE docker ARG at the top of the file.

ARG BASE=golang:1.15-alpine\nFROM ${BASE}\n...\n

This allows Jenkins to override the base image during the build with an image from Nexus helping to alleviate issues with DockerHub pull limits as well as random Docker pull failures. On Jenkins this happens in the Prep stage:

docker build -t ci-base-image-x86_64 \\\n-f Dockerfile.build \\\n--build-arg BASE=nexus3.edgexfoundry.org:10003/edgex-devops/edgex-golang-base:1.15-alpine \\\n.\n

The DevOps WG team manages these Golang base images and the Dockerfile for the latest Golang image used can be found here: https://github.com/edgexfoundry/ci-build-images/tree/golang-1.15. This cache image contains most of the dependencies used in the majority of the pipelines allowing us to cache dependencies at the base image level and increasing builds speeds.

After the base image is built the test and build stages run in a similar manner to the local testing scenario:

docker run -t -u 0:0 \\\n  -w /w/workspace/app-service-configurable/60 \\\n  -v /w/workspace/app-service-configurable/60:/w/workspace/app-service-configurable/60:rw,z \\\n  -v /w/workspace/app-service-configurable/60@tmp:/w/workspace/app-service-configurable/60@tmp:rw,z \\\n  ci-base-image-x86_64 ... make test\n
"},{"location":"tutorials/docker-build-strategy/#next-steps","title":"Next steps","text":"

More information can be found by reading the documentation or source code of these pipelines:

  • edgeXBuildGoApp source
  • edgeXBuildGoParallel source
"},{"location":"tutorials/manual-bump/","title":"Manual Version Bump Process","text":"

Sometimes the version of the edgex-global-pipelines needs to be changed between stable and experimental tags in order to enhance and validate that the changes work as expected.

The process documented here outlines the manual process for bumping the version and tag on the global libraries.

"},{"location":"tutorials/manual-bump/#committer-access-required","title":"Committer Access Required","text":"

You must have write access to the repo to perform this manual version bump process. - Developer must be a member of the devops-core-team as per TSC approval - Version info can be obtained through view of the Jenkins Pipeline log for last successful build

$ git clone git@github.com:edgexfoundry/edgex-global-pipelines.git\n$ cd edgex-global-pipelines\n$ ./resources/update-named-tag.sh <version> <stable|experimental>\n
"},{"location":"tutorials/manual-bump/#click-on-image-below-to-view-ascii-recording-of-the-manual-version-bump-process","title":"Click on image below to view ASCII recording of the manual version bump process","text":""},{"location":"tutorials/pr-commit-for-testing/","title":"Pull Request Sandbox Testing","text":""},{"location":"tutorials/pr-commit-for-testing/#introduction","title":"Introduction","text":"

The EdgeX Jenkins Production Server and EdgeX Jenkins Sandbox Server are configured to use the edgex-global-pipelines library. The servers target either stable or experimental tags for Production and Sandbox servers respectively.

To make functional testing of Jenkins Shared Pipeline Libraries more convenient, you can use a commit hash from a Pull Request into edgex-global-pipelines to override the default pipeline version that the Jenkins server is using. (stable/experimental)

"},{"location":"tutorials/pr-commit-for-testing/#step-1-create-draft-pr","title":"Step 1 - Create Draft PR","text":"

When you have changes you'd like to functionally test, open a Draft Pull Request from your forked repository of edgex-global-pipelines into edgex-global-pipelines:main

Make clear that this is a PR for functional testing purposes and is not meant to be merged.

"},{"location":"tutorials/pr-commit-for-testing/#step-2-use-pr-commit-hash","title":"Step 2 - Use PR Commit Hash","text":"

Find the commit hash of your draft PR.

Place the commit hash into your Jenkinsfile that is under test. The EdgeX Sample-Service is a good place to functionally test shared libraries without affecting production code.

Add the commit hash after the '@' in the explicit library import statement as shown below.

@Library(\"edgex-global-pipelines@7eba319\") _\n\nedgeXBuildGoApp (\nproject: 'sample-service',\n    goVersion: '1.15',\n    buildExperimentalDockerImage: true\n)\n
"},{"location":"tutorials/pr-commit-for-testing/#step-3-execute-jenkinsfile","title":"Step 3 - Execute Jenkinsfile","text":"

When you execute your functional test build job on the sandbox, the commit hash of your PR will be shown as the commit used for the edgex-global-pipeline shared library. You will see a message similar to the following in your build job console output.

...\nLoading library edgex-global-pipelines@7eba319\nAttempting to resolve 7eba319 from remote references...\n...\n
"},{"location":"tutorials/pr-commit-for-testing/#step-4-finishing-up","title":"Step 4 - Finishing Up","text":"

When you are satisfied that the content of your edgex-global-pipelines fork is functionally tested and ready to be merged, you can convert your draft PR into a real PR and add the appropriate reviewers.

After your PR is merged to main, the experimental tag will point to your newest content. You might want to test your new code by switching back to the experimental tag in your Jenkinsfile.

@Library(\"edgex-global-pipelines@experimental\") _\n

Please clean up and close your PR after you have finished your functional testing.

"},{"location":"tutorials/unit-testing-best-practices/","title":"Unit Testing Best Practices","text":""},{"location":"tutorials/unit-testing-best-practices/#table-of-contents","title":"Table Of Contents","text":"
  • Unit Testing Declarative Pipelines
  • Encapsulate Pipeline logic within Groovy functions
  • Example
  • Mocking Jenkins Dependencies
  • Add plugin dependency to Gradle
  • Mocking Environment Variables
  • Testing environment variables
  • Mock external shared library methods
  • Integration Testing
  • Mock errors
  • Mock external shared library methods
  • Call Graph Example
  • References
"},{"location":"tutorials/unit-testing-best-practices/#unit-testing-declarative-pipelines","title":"Unit Testing Declarative Pipelines","text":"

The edgex-global-pipelines shared library leverages the Jenkins Spock framework for unit testing Jenkins pipeline scripts and functions. The Jenkins Spock unit test framework does not currently support unit testing of Jenkins Declarative Pipeline code.

"},{"location":"tutorials/unit-testing-best-practices/#encapsulate-pipeline-logic-within-groovy-functions","title":"Encapsulate Pipeline logic within Groovy functions","text":"

In order to facilitate unit testing of the edgex-global-pipelines shared library, the DevOps team has made a deliberate effort to to minimize the amount of scripting logic contained within Jenkins declarative pipelines. This is accomplished by encapsulating pipeline logic within a Groovy function and calling the function in the declarative pipeline step as needed. Localizing pipeline logic within Groovy functions enables the Jenkins Spock framework to provide greater test coverage of Pipeline logic.

"},{"location":"tutorials/unit-testing-best-practices/#example","title":"Example","text":"

An example this approach can be seen within the Build -> amd64 -> Prep stage of the edgeXBuildCApp Delcarative Pipeline. Note the logic for prepping the base build image is encapsulated into a method named prepBaseBuildImage and it is called within the declarative Pipeline. Also the prepBaseBuildImage function logic is thoroughly unit tested in the edgeXBuildCApp Spec

"},{"location":"tutorials/unit-testing-best-practices/#mocking-jenkins-dependencies","title":"Mocking Jenkins Dependencies","text":"

Always leverage the builtin capabilities of the Jenkins-Spock framework for mocking Jenkins plugins. For example, if you come across the following error when unit testing your code:

java.lang.IllegalStateException: During a test, the pipeline step [stepName] was called but there was no mock for it.\n
The error above denotes that the code under test calls a pipeline step stepName but there is no mock for it. You are able to explicitly mock the pipeline step using explictlyMockPipelineStep method available in the Jenkins-Spock framework. However it is recommended that the plugin that contains the corresponding step be added as a dependency in the build.gradle file. For instructions on how to do this, refer to the Add plugin dependency to Gradle section.

"},{"location":"tutorials/unit-testing-best-practices/#add-plugin-dependency-to-gradle","title":"Add plugin dependency to Gradle","text":"
  1. Note the name of the Pipeline Step to add.
  2. Go to Pipeline Steps Reference page.
  3. Use your browser and search for the Pipeline Step within the page.
  4. If the Pipeline Step is found, click on the Pipeline that it belongs to, the page for the respective Pipeline should open.
  5. Under the heading click on the View this plugin on the Plugins site link, the plugins.jenkins.io page should open.
  6. In the plugins.jenkins.io page note the ID for the Pipeline. You will use this ID in the next step.
  7. Go to Maven Repository page.
  8. Enter the ID in the search, and locate the result from the results displayed, click on the respective link.
  9. In the page, click on the Jenkins Releases tab.
  10. If you know the version then click it, otherwise click on the latest version that is listed.
  11. In the Gradle tab, note the group, name and version.
  12. Edit the build.gradle file, add the dependency found above to the dependencies section.
"},{"location":"tutorials/unit-testing-best-practices/#mocking-environment-variables","title":"Mocking Environment Variables","text":"

Always ensure the source code under test uses one of the following idioms for getting or setting Environment Variables, doing this will simplify the ability to mock environment variables in the unit test: - Getting the value of an environment variable - env.VARIABLE - env[VARIABLE] - \"${env.VARIABLE}\" - Setting the value of an environment variable - env.VARIABLE = VALUE - env[VARIABLE] = VALUE

"},{"location":"tutorials/unit-testing-best-practices/#testing-environment-variables","title":"Testing environment variables","text":"

Within your unit tests, environment variables are set using the .getBinding().setVariable('name', 'value') idiom. Where the name is env and the value is a map you define within your unit test. The map should define all environment variables the code under test expects, likewise the map can be used to assert any environment variables that the code under test sets.

A good example of this practice is the EdgeXSetupEnvironmentSpec

"},{"location":"tutorials/unit-testing-best-practices/#mock-external-shared-library-methods","title":"Mock external shared library methods","text":"

The edgex-global-pipelines Jenkins shared library consists of multiple scripts exposing methods for various functional areas, where each script is named after the particular functional area it serves. The shared library includes a EdgeX script that serves as utility script containing methods that are shared amongst other scripts. It is common practice for a method in one script call a method in another script, to mock the interaction you use the explictlyMockPipelineVariable to mock the script, then getPipelineMock method to verify the interaction or stub it if necessary.

Mock the external script named script:

explictlyMockPipelineVariable('script')\n
It is recommended to mock all external scripts called within the script under test in the Test Spec setup.

Get the script mock and stub the call to method to return 'value' for any argument passed in:

getPipelineMock('script.method').call(_) >> 'value'\n

"},{"location":"tutorials/unit-testing-best-practices/#integration-testing","title":"Integration Testing","text":"

Integration Testing is defined as a type of testing where software modules are integrated logically and tested as a group. The Jenkins-Spock framework provides the ability to load any number of scripts to test within a given Spec Test. There are instances where performing integration tests is more practical, if you wish to do so then we recommend naming the Spec Test with Int as to differentiate between unit and integration tests.

A good example of this practice is the EdgeXReleaseDockerImageIntSpec

"},{"location":"tutorials/unit-testing-best-practices/#mock-errors","title":"Mock errors","text":"

Always leverage error when wanting to conditionally terminate part of your script. Error is a Pipeline Step whose plugin has been added as a dependency to our project thus is already mocked by the framework. An example showing how you can assert that an error is thrown with a specific message:

1 * getPipelineMock('error').call('error message')\n

"},{"location":"tutorials/unit-testing-best-practices/#mock-external-shared-library-methods_1","title":"Mock external shared library methods","text":"

The difficulties of mocking functions within the same script under test have been described in the following issue: Issue 78. Due to the nature of how the scripts that comprise the edgex-global-pipelines shared library are written; where a deliberate intent is made to develop small, functionally cohesive methods that contribute to a single well-defined task. This development intent results in having scripts with multi-layered call graphs, where methods may call multiple methods from within the same script. We find that the workaround provided in the issue is complicated and doesn't scale well in our environment. For these reasons the method outlined below is being suggested.

  1. For the script under test, document its call graph. A call graph is a control flow graph, which represents calling relationships between methods in a script or program. Each node represents a method and each edge (f, g) indicates that method f calls method g. An example EdgeXReleaseGitTag call graph is depicted below.
  2. Create a second script with the same name as the original script with the word Util added to the end, for example EdgeXReleaseGitTagUtil.groovy.
  3. Analyze the call graph, methods that reside in odd numbered layers should continue to reside in the first script, methods at even numbered layers should be moved from the first script into the second script.
  4. Create a Spec Test for both scripts.

Mocking of methods between both scripts follow the same pattern described for Mock external shared library methods. The only difference with this approach is that the scripts are (for the lack of a better word) name spaced for the respective functional area.

"},{"location":"tutorials/unit-testing-best-practices/#call-graph-example","title":"Call Graph Example","text":"

NOTE The approach outlined above is not recommended as the standard development approach, but as an alternative to re-writing the script under test if mocking of the internal method calls becomes unwieldy.

"},{"location":"tutorials/unit-testing-best-practices/#references","title":"References","text":"
  • Jenkins Spock Documentation
  • Spock Framework Reference
  • Jenkins Shared Libraries
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"EdgeX Global Pipelines","text":""},{"location":"#summary","title":"Summary","text":"

This repository contains useful Jenkins global library functions used within the EdgeX Jenkins ecosystem. It provides pre-built pipelines to build and publish Go/C++ based source code in a consistent manner. There are also a lot of utility functions that allow for things like automated vulnerability scanning via Snyk, code coverage tracking via CodeCov.io and many other things. Below you will find some useful links as well as links to all of our documented pipelines.

Please note: Documentation is still under heavy development.

"},{"location":"#useful-links","title":"Useful Links","text":"
  • Source Code
  • EdgeX Jenkins Server
  • Jenkins Shared Libraries
"},{"location":"#jenkins-shared-libraries","title":"Jenkins Shared Libraries","text":"
  • edgeXBuildCApp
  • edgeXBuildDocker
  • edgeXBuildGoApp
  • edgeXBuildGoMod
  • edgeXBuildGoParallel
  • edgeXClair
  • edgeXCodecov
  • edgeXDocker
  • edgeXDockerLogin
  • edgeXEmail
  • edgeXEmailUtil
  • edgeXGHPagesPublish
  • edgeXGeneric
  • edgeXInfraLFToolsSign
  • edgeXInfraPublish
  • edgeXInfraShipLogs
  • edgeXLTS
  • edgeXNexusPublish
  • edgeXRelease
  • edgeXReleaseDockerImage
  • edgeXReleaseDocs
  • edgeXReleaseGitHubAssets
  • edgeXReleaseGitTag
  • edgeXReleaseGitTagUtil
  • edgeXReleaseOpenApi
  • edgeXReleaseSnap
  • edgeXSemver
  • edgeXSetupEnvironment
  • edgeXSnap
  • edgeXSnyk
  • edgeXSwaggerPublish
  • edgeXUpdateNamedTag
  • edgex
"},{"location":"libraries/edgeXBuildCApp/","title":"edgeXBuildCApp","text":"

Shared Library to build C projects

"},{"location":"libraries/edgeXBuildCApp/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildCApp/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build dockerBaseImage optional str The docker base image for your project.Default: nexus3.edgexfoundry.org:10003/edgex-devops/edgex-gcc-base:latest dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to false.Default: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildCApp/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildCApp/#basic-example","title":"Basic example","text":"
edgeXBuildCApp (\nproject: 'device-bacnet-c'\n)\n
"},{"location":"libraries/edgeXBuildCApp/#complex-example","title":"Complex example","text":"
edgeXBuildCApp (\nproject: 'device-sdk-c',\ndockerBuildFilePath: 'scripts/Dockerfile.alpine-3.11-base',\ndockerFilePath: 'scripts/Dockerfile.alpine-3.11',\ntestScript: 'apk add --update --no-cache openssl ca-certificates && make test',\npushImage: false\n)\n
"},{"location":"libraries/edgeXBuildCApp/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildCApp (\nproject: 'c-project',\nmavenSettings: 'c-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ndockerBaseImage: 'nexus3.edgexfoundry.org:10003/edgex-devops/edgex-gcc-base:latest',\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-c-project',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildDocker/","title":"edgeXBuildDocker","text":"

Shared Library to build docker images

"},{"location":"libraries/edgeXBuildDocker/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildDocker/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerTags optional str The tag name for your docker image.Default: [] dockerPushLatest optional str Specify if Jenkins should push the docker image with latest tag. Default: true dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true archiveImage optional bool Specify if the built image need to be archived.Default: false archiveName optional bool The name of the archived image.Default: ${_projectName}-archive.tar.gz semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre releaseBranchOverride optional str Specify if you want to override the release branch. failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildDocker/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildDocker/#basic-example","title":"Basic example","text":"
edgeXBuildDocker (\nproject: 'docker-edgex-consul',\ndockerImageName: 'docker-edgex-consul',\nsemver: true\n)\n
"},{"location":"libraries/edgeXBuildDocker/#complex-example","title":"Complex example","text":"
edgeXBuildDocker (\nproject: 'edgex-compose',\nmavenSettings: 'ci-build-images-settings',\ndockerImageName: 'custom-edgex-compose',\ndockerNamespace: 'edgex-devops',\ndockerNexusRepo: 'snapshots',\ndockerTags: [\"1.24.1\"],\nreleaseBranchOverride: 'edgex-compose'\n)\n
"},{"location":"libraries/edgeXBuildDocker/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildDocker (\nproject: 'sample-project',\nmavenSettings: 'sample-project-settings',\nsemver: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-sample-project',\ndockerTags: [],\ndockerPushLatest: true,\ndockerNexusRepo: 'staging',\npushImage: true,\narchiveImage: false,\narchiveName: sample-project-archive.tar.gz,\nsemverBump: 'pre',\nreleaseBranchOverride: 'golang',\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildGoApp/","title":"edgeXBuildGoApp","text":"

Shared Library to build Go projects

"},{"location":"libraries/edgeXBuildGoApp/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildGoApp/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build goVersion optional str The version of Go to use for building the project's CI build image. Note this parameter is used in conjuction with the useAlpineBase parameter to determine the base for the project's CI build image.Default: 1.20 goProxy optional str The proxy to use when downloading Go modules. The value of this parameter will be set in the GOPROXY environment variable to control the download source of Go modules.Default: https://nexus3.edgexfoundry.org/repository/go-proxy/ useAlpineBase optional bool Specify if an Alpine-based edgex-golang-base:${goVersion}-alpine image will be used as the base for the project's CI build image. If true, the respective edgex-golang-base image should exist in the Nexus snapshot repository, if a matching image is not found in Nexus then an Alpine-based go-lang:${goVersion}-alpine DockerHub image will be used. If false, then a non-Alpine go-lang:${goVersion} DockerHub image will be used. Note this parameter is used in conjuction with the goVersion parameter to determine the base for the projects' CI build image.Default: true dockerFilePath optional str The path to the Dockerfile for your project.Default: Dockerfile dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerBuildArgs optional list The list of additonal arguments to pass to Docker when building the image for your project.Default: [] dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerImageName optional str The name of the Docker image for your project.Default: docker-${project} dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker image dockerImageName will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to false.Default: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre semverVersion optional str This parameter isn't currently used and will be removed in a future version.Default: '' buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false publishSwaggerDocs optional bool Specify if Jenkins should attempt to publish your projects API documentation to SwaggerHub. Note in order for Jenkins to publish to SwaggerHub you must ensure a valid value for swaggerApiFolders is set.Default: false swaggerApiFolders optional list The list of paths to your projects API Swagger-based documentation.Default: ['openapi/v1'] failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org buildExperimentalDockerImage optional bool Specify if Jenkins should add an additonal GitHub tag called experimental at the same commit where the semantic version is tagged. Note this feature is currently only used internally for DevOps builds.Default: false artifactTypes optional list A list of types that the Jenkins build will designate as artifacts, valid list values are docker and archive. Note if archive is specified then all tar.gz or zip files that your project build creates in the artifactRoot folder will be archived to Nexus.Default: ['docker'] artifactRoot optional str The path in the Jenkins workspace to designate as the artifact root folder. Note all files written to this directory within your build will be automatically pushed to Nexus when the Jenkins job completes.Default: archives/bin arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildGoApp/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoApp/#basic-example","title":"Basic example","text":"
edgeXBuildGoApp (\nproject: 'device-random-go',\ngoVersion: '1.16'\n)\n
"},{"location":"libraries/edgeXBuildGoApp/#complex-example","title":"Complex example","text":"
edgeXBuildGoApp (\nproject: 'app-functions-sdk-go',\nsemver: true,\ngoVersion: '1.16',\ntestScript: 'make test',\nbuildImage: false,\npublishSwaggerDocs: true,\nswaggerApiFolders: ['openapi/v2']\n)\n
"},{"location":"libraries/edgeXBuildGoApp/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoApp (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-go-project',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\nbuildExperimentalDockerImage: false,\nartifactTypes: ['docker'],\nartifactRoot: 'archives/bin',\narch: ['amd64', 'arm64']\n\n)\n
"},{"location":"libraries/edgeXBuildGoMod/","title":"edgeXBuildGoMod","text":"

Shared Library to build Go projects using Go Modules. It invokes edgeXBuildGoApp with some default parameters.

"},{"location":"libraries/edgeXBuildGoMod/#parameters","title":"Parameters","text":"

The parameters are similar to shared Library edgeXBuildGoApp with a few exceptions in default values of some parameters.

buildImage: false,\npushImage: false,\nsemverBump: 'pre'\n
** Note:** These parameters are not overridable.

"},{"location":"libraries/edgeXBuildGoMod/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoMod/#basic-example","title":"Basic example","text":"
edgeXBuildGoMod (\nproject: 'go-mod-configuration'\n)\n
"},{"location":"libraries/edgeXBuildGoMod/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoMod (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFilePath: 'Dockerfile',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerBuildArgs: [],\ndockerNamespace: '',\ndockerImageName: 'docker-go-project',\ndockerNexusRepo: 'staging',\nbuildImage: false,\npushImage: false,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\nbuildExperimentalDockerImage: false,\nartifactTypes: ['docker'],\nartifactRoot: 'archives/bin',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/","title":"edgeXBuildGoParallel","text":"

Shared Library to build Go projects and Docker images in parallel. Utilizes docker compose --parallel to build Docker images found in the workspace. Currently only used for the edgex-go mono-repo.

"},{"location":"libraries/edgeXBuildGoParallel/#overview","title":"Overview","text":""},{"location":"libraries/edgeXBuildGoParallel/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value project required str The name of your project. mavenSettings optional str The maven settings file in Jenkins that has been created for your project. Note the maven settings file specified must exist in Jenkins in order for your project to build.Default: ${project}-settings semver optional bool Specify if semantic versioning will be used to version your project. Note edgeX utilizes git-semver for semantic versioning.Default: true testScript optional str The command the build will use to test your project. Note the specified test script will execute in the project's CI build container.Default: make test buildScript optional str The command the build will use to build your project.Default: make build goVersion optional str The version of Go to use for building the project's CI build image. Note this parameter is used in conjuction with the useAlpineBase parameter to determine the base for the project's CI build image.Default: 1.20 goProxy optional str The proxy to use when downloading Go modules. The value of this parameter will be set in the GOPROXY environment variable to control the download source of Go modules.Default: https://nexus3.edgexfoundry.org/repository/go-proxy/ useAlpineBase optional bool Specify if an Alpine-based edgex-golang-base:${goVersion}-alpine image will be used as the base for the project's CI build image. If true, the respective edgex-golang-base image should exist in the Nexus snapshot repository, if a matching image is not found in Nexus then an Alpine-based go-lang:${goVersion}-alpine DockerHub image will be used. If false, then a non-Alpine go-lang:${goVersion} DockerHub image will be used. Note this parameter is used in conjuction with the goVersion parameter to determine the base for the projects' CI build image.Default: true dockerFileGlobPath optional str The pattern for finding Dockerfiles to build. Note Docker images will be named with the same name as the directory which the Dockerfile was found in with a docker- prefix and -go suffix. Example: docker-<folder>-goDefault: cmd/** /Dockerfile dockerImageNamePrefix optional str The prefix to apply to the names of all the Docker images built.Default: docker- dockerImageNameSuffix optional str The suffix to apply to the names of all the Docker images built.Default: -go dockerBuildFilePath optional str The path to the Dockerfile that will serve as the CI build image for your project.Default: Dockerfile.build dockerBuildContext optional str The path for Docker to use as its build context when building your project. This applies to building both the CI build image and project image.Default: . dockerBuildImageTarget optional str The name of the docker multi-stage-build stage the pipeline will use when building the CI build image.Default: builder dockerNamespace optional str The docker registry namespace to use when publishing Docker images. Note for EdgeX projects images are published to the root of the docker registry and thus the namespace should be empty.Default: '' dockerNexusRepo optional str The name of the Docker Nexus repository where the project Docker images will be published to if pushImage is set.Default: staging buildImage optional bool Specify if Jenkins should build a Docker image for your project. Note if false then pushImage will also be set to falseDefault: true pushImage optional bool Specify if Jenkins should push your project's image to dockerNexusRepo.Default: true semverBump optional str The semver axis to bump, see git-semver for valid axis values.Default: pre buildSnap optional bool Specify if Jenkins should build a Snap for your project. Note If set, your project must also include a valid snapcraft yaml snap/snapcraft.yaml for Jenkins to attempt to build the Snap.Default: false publishSwaggerDocs optional bool Specify if Jenkins should attempt to publish your projects API documentation to SwaggerHub. Note in order for Jenkins to publish to SwaggerHub you must ensure a valid value for swaggerApiFolders is set.Default: false swaggerApiFolders optional list The list of paths to your projects API Swagger-based documentation.Default: ['openapi/v1', 'openapi/v2'] failureNotify optional str The group emails (comma-delimited) to email when the Jenkins job fails.Default: edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org arch optional array A list of system architectures to target for the build. Possible values are amd64 or arm64.Default: ['amd64', 'arm64']"},{"location":"libraries/edgeXBuildGoParallel/#usage","title":"Usage","text":""},{"location":"libraries/edgeXBuildGoParallel/#basic-example","title":"Basic example","text":"
edgeXBuildGoParallel (\nproject: 'edgex-go',\ndockerFileGlobPath: 'cmd/** /Dockerfile',\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/#complex-example","title":"Complex example","text":"
edgeXBuildGoParallel(\nproject: 'edgex-go',\ndockerFileGlobPath: 'cmd/** /Dockerfile',\ntestScript: 'make test',\nbuildScript: 'make build',\npublishSwaggerDocs: true,\nswaggerApiFolders: ['openapi/v1', 'openapi/v2'],\nbuildSnap: true\n)\n
"},{"location":"libraries/edgeXBuildGoParallel/#full-example","title":"Full example","text":"

This example shows all the settings that can be specified and their default values.

edgeXBuildGoParallel (\nproject: 'go-project',\nmavenSettings: 'go-project-settings',\nsemver: true,\ntestScript: 'make test',\nbuildScript: 'make build',\ngoVersion: '1.16',\ngoProxy: 'https://nexus3.edgexfoundry.org/repository/go-proxy/',\nuseAlpineBase: true,\ndockerFileGlobPath: 'cmd/** /Dockerfile',\ndockerImageNamePrefix: 'docker-',\ndockerImageNameSuffix: '-go',\ndockerBuildFilePath: 'Dockerfile.build',\ndockerBuildContext: '.',\ndockerNamespace: '',\ndockerNexusRepo: 'staging',\nbuildImage: true,\npushImage: true,\nsemverBump: 'pre',\nbuildSnap: false,\npublishSwaggerDocs: false,\nswaggerApiFolders: ['openapi/v1', 'openapi/v2'],\nfailureNotify: 'edgex-tsc-core@lists.edgexfoundry.org,edgex-tsc-devops@lists.edgexfoundry.org',\narch: ['amd64', 'arm64']\n)\n
"},{"location":"libraries/edgeXClair/","title":"edgeXClair","text":"

\u26a0\ufe0f Deprecated will be removed in a future version. DO NOT USE \u26a0\ufe0f

Shared library function to scan docker images for vulnerabilities using Klar. Please use edgeXSnyk instead.

"},{"location":"libraries/edgeXCodecov/","title":"edgeXCodecov","text":""},{"location":"libraries/edgeXCodecov/#overview","title":"Overview","text":"

Shared library to publish Codecov results to CodeCov.io

"},{"location":"libraries/edgeXCodecov/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value tokenFile false str Id of managed config file where token is stored. If null or empty, token file is automatically generated with: ${env.PROJECT}-codecov-token"},{"location":"libraries/edgeXCodecov/#usage","title":"Usage","text":"
edgeXCodecov('sample-service-codecov-token')\n
"},{"location":"libraries/edgeXDocker/","title":"edgeXDocker","text":""},{"location":"libraries/edgeXDocker/#overview","title":"Overview","text":"

Shared library that contains convenience functions for interacting with Docker. This shared library contains numerous functions so only a summary will be provided for each given function. If you have further questions about implementation details please refer to the source code.

"},{"location":"libraries/edgeXDocker/#functions","title":"Functions:","text":"
  • edgeXDocker.build: Build a docker image from optional baseImage with a set of default: docker build_args, labels, and tags.
  • edgeXDocker.buildInParallel: Build multiple docker images in parallel. This technique utilizes docker compose to build multiple images using the parallel flag.
  • edgeXDocker.generateDockerComposeForBuild: Supporting function for edgeXDocker.buildInParallel that generates a docker compose file for a given list of docker images.
  • edgeXDocker.generateServiceYaml: Supporting function for edgeXDocker.buildInParallel that generates service level yaml for a specific docker image.
  • edgeXDocker.push: Push a specific docker image and optionally tag it with the latest tag. A nexus repository can also optionally be specified as well as specific tags.
  • edgeXDocker.pushAll: Push all docker images specified in the dockerImages list. To be used in conjunction with the same input format used by edgeXDocker.buildInParallel to push all images.
  • edgeXDocker.getDockerTags: Generates the default set of tags used when pushing all edgex docker images with the edgeXDocker.push function.
  • edgeXDocker.finalImageName: Prepends a docker image with env.DOCKER_REGISTRY_NAMESPACE if defined.
  • edgeXDocker.cleanImageUrl: Returns image url without protocol.
  • edgeXDocker.parse: Reads a docker image url and returns the parsed image object components.
  • edgeXDocker.toImageStr: Returns docker image string from an image object.
"},{"location":"libraries/edgeXDocker/#parsed-image-object","title":"Parsed image object","text":"
[\nhost: hostname if any associated with the image,\nfullImage: full image name with tag,\nnamespace: namespace of the image if any,\nimage: image name without tag,\ntag: tag associated with the image if any\n]\n
"},{"location":"libraries/edgeXDockerLogin/","title":"edgeXDockerLogin","text":""},{"location":"libraries/edgeXDockerLogin/#overview","title":"Overview","text":"

Shared library that wraps the Linux Foundation's (LF) docker login script: ./resources/global-jjb/shell/docker-login.sh.

The LF Global JJB Docker Login script looks for the following environment variables: $SETTINGS_FILE, $DOCKER_REGISTRY, $REGISTRY_PORTS, $DOCKERHUB_REGISTRY, $DOCKERHUB_EMAIL which this script automatically sets. Based on given config map entries passed in

Please refer to the shell script in global-jjb/shell for the usage.

"},{"location":"libraries/edgeXDockerLogin/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value settingsFile true str Config file Id that contains authentication details to docker registries. Unique to each Edgex repository. dockerRegistry false str Override docker registry to login to. dockerRegistryPorts false str Listing of all the registry ports to login to e.g.: 10001 10002 10003 10004 dockerHubRegistry false str Override docker hub registry. Not commonly used. dockerHubEmail false str Override docker hub email. Not commonly used."},{"location":"libraries/edgeXDockerLogin/#usage","title":"Usage","text":"
edgeXDockerLogin(settingsFile: 'edgex-repo-settings')\n
"},{"location":"libraries/edgeXEmail/","title":"edgeXEmail","text":""},{"location":"libraries/edgeXEmail/#overview","title":"Overview","text":"

Shared library to send build success/fail emails generated by the edgexEmailUtil.generateEmailTemplate function.

"},{"location":"libraries/edgeXEmail/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value subject false str Email subject. Default: [${buildStatus}] ${env.JOB_NAME} Build #${env.BUILD_NUMBER} emailTo true str Comma separated list of email address(s) to send email to."},{"location":"libraries/edgeXEmail/#usage","title":"Usage","text":"
edgeXEmail(emailTo: 'bob@example.com,susan@example.com')\n
"},{"location":"libraries/edgeXEmailUtil/","title":"edgeXEmailUtil","text":""},{"location":"libraries/edgeXEmailUtil/#overview","title":"Overview","text":"

Shared library to support the edgeXEmail function by returning relevant build information that can be used to generate an email template. Email template can be found here: https://github.com/edgexfoundry/edgex-global-pipelines/tree/main/resources/email

"},{"location":"libraries/edgeXEmailUtil/#function-overview","title":"Function Overview","text":"
  • edgeXEmailUtil.getJobDetailsJson: Extract relevant build details including job information, author, git information, and failure log information and return map of details.
  • edgeXEmailUtil.generateEmailTemplate: Generate HTML email template from given job details usually generated by calling edgeXEmailUtil.getJobDetailsJson(). Email templates utilize mustache templates and leverage mustachejs for rendering.
"},{"location":"libraries/edgeXEmailUtil/#usage","title":"Usage","text":"
def jobDetails = edgeXEmailUtil.getJobDetailsJson()\ndef emailHtml  = edgeXEmailUtil.generateEmailTemplate(jobDetails)\n\n// do something with emailHtml...\n
"},{"location":"libraries/edgeXGHPagesPublish/","title":"edgeXGHPagesPublish","text":""},{"location":"libraries/edgeXGHPagesPublish/#overview","title":"Overview","text":"

Shared library to publish html and other resources to a GitHub pages branch off the main repository (typically gh-pages). This shared library is typically used in conjunction with mkdocs and after mkdocs generates all the HTML, etc and the calling pipeline stashes the contents into a specific site-contents Jenkins stash.

"},{"location":"libraries/edgeXGHPagesPublish/#process","title":"Process","text":"

The typical documentation build process goes like this:

  • PR is merged into main in upstream repo
  • mkdocs is called to generate final documentation in upstream repo job.
  • site-contents stash is generated in upstream repo job.
  • edgeXGHPagesPublish() is called to publish stash to GitHub pages.
"},{"location":"libraries/edgeXGHPagesPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value repoUrl true str Repo URL where GitHub pages are being published (typically in ssh format for Edgex). credentialId false str Jenkins credentialId used to authenticate to git to push contents. Default: edgex-jenkins-ssh ghPagesBranch false str Git branch where GitHub pages are stored. Default: gh-pages stashName false str Stash name that contains generated site contents that will be published. Default: site-contents"},{"location":"libraries/edgeXGHPagesPublish/#usage","title":"Usage","text":"
edgeXGHPagesPublish((repoUrl: 'git@github.com:edgexfoundry/edgex-docs.git')\n
"},{"location":"libraries/edgeXGeneric/","title":"edgeXGeneric","text":"

\u26a0\ufe0f Deprecated will be removed in a future version. DO NOT USE \u26a0\ufe0f

edgeXGeneric([\nproject: 'edgex-go',\nmavenSettings: ['edgex-go-codecov-token:CODECOV_TOKEN'], (optional)\ncredentials: [string(credentialsId: 'credential-id-here', variable: 'APIKEY')], (optional)\nenv: [\nGOPATH: '/opt/go-custom/go'\n],\npath: [\n'/opt/go-custom/go/bin'\n],\nbranches: [\n'*': [\npre_build: ['shell/install_custom_golang.sh'],\nbuild: [\n'make test raml_verify && make build docker',\n'shell/codecov-uploader.sh'\n]\n],\n'main': [\npost_build: [ 'shell/edgexfoundry-go-docker-push.sh' ]\n]\n]\n])\n
"},{"location":"libraries/edgeXInfraLFToolsSign/","title":"edgeXInfraLFToolsSign","text":""},{"location":"libraries/edgeXInfraLFToolsSign/#overview","title":"Overview","text":"

Shared library that wraps signing of git tags or files in a directory using lftools and Sigul. The signing is done inside a docker image managed by the EdgeX DevOps team.

Important: Signing git tags, requires the git tag to be an annotated tag. (git tag -a)

"},{"location":"libraries/edgeXInfraLFToolsSign/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value sigulConfig false str Config file Id that contains the Sigul config. Default: sigul-config sigulPassword false str Config file Id that contains the Sigul password. Default: sigul-password sigulPKI false str Config file Id that contains the Sigul PKI information. Default: sigul-pki lftoolsImageVersion false str DevOps managed lftools image version tag. Default: 0.23.1-centos7 command true str Command to run. Valid values: dir, git-tag directory true str Required if command is dir. version true str Required if command is git-tag. mode false str lftools sign mode. Default: parallel"},{"location":"libraries/edgeXInfraLFToolsSign/#usage","title":"Usage","text":"
edgeXInfraLFToolsSign(command: 'git-tag', version: 'v2.0.0')\n
edgeXInfraLFToolsSign([command: 'dir', directory: 'MyDirectory'])\n
"},{"location":"libraries/edgeXInfraPublish/","title":"edgeXInfraPublish","text":""},{"location":"libraries/edgeXInfraPublish/#overview","title":"Overview","text":"

Shared library used as a post build stage to publish build artifacts, logs, metrics to EdgeX Nexus server.

"},{"location":"libraries/edgeXInfraPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value logSettingsFile false str Config file id for settings to authenticate to Nexus to publish build logs. Default: jenkins-log-archives-settings dockerOptimized false str Whether or not to use a docker image when publishing to Nexus. Default: true"},{"location":"libraries/edgeXInfraPublish/#usage","title":"Usage","text":"
edgeXInfraPublish()\n
edgeXInfraPublish {\nlogSettingsFile = 'custom-jenkins-log-archives-settings'\ndockerOptimized = false\n}\n
"},{"location":"libraries/edgeXInfraShipLogs/","title":"edgeXInfraPublish","text":"

\u26a0\ufe0f Deprecated no longer in use. This has been replace by lfInfraShipLogs. DO NOT USE \u26a0\ufe0f

"},{"location":"libraries/edgeXLTS/","title":"edgeXLTS","text":""},{"location":"libraries/edgeXLTS/#overview","title":"Overview","text":"

Shared library with helper functions to manage LTS releases. Used as part of the edgeXRelease.groovy pipeline.

"},{"location":"libraries/edgeXLTS/#functions","title":"Functions:","text":"
  • edgeXLTS.prepLTS: Prepares a repository for an LTS release. If the repository is Golang based, go vendoring is enabled to support LTS releases.
  • edgeXLTS.getLatestLTSCommitId: Retrieves the latest LTS commit sha from a repository.
  • edgeXLTS.generateLTSCommitMessage: Creates a an LTS commit message for a release.
  • edgeXLTS.prepGoProject: Prepares a Golang based project for an LTS release enable vendoring and removing the vendor directory from the gitignore file.
"},{"location":"libraries/edgeXNexusPublish/","title":"edgeXNexusPublish","text":""},{"location":"libraries/edgeXNexusPublish/#overview","title":"Overview","text":"

Shared library to publish a ZIP file to a specific nexus repo.

"},{"location":"libraries/edgeXNexusPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value serverId true str Used to lookup credentials in mavenSettings file. Example: logs, docker, nexus.edgexfoundry.org mavenSettings true str Config file Id to use publish to Nexus. Example: log-settings nexusRepo true str The nexus repository name where you would like to publish your artifacts. nexusPath false str Path on the nexus server where file should be stored. Default:${env.SILO}/${env.JENKINS_HOSTNAME}/${env.JOB_NAME}/${env.BUILD_NUMBER} zipFilePath true str path to ZIP file, typically in the workspace."},{"location":"libraries/edgeXNexusPublish/#usage","title":"Usage","text":"
edgeXNexusPublish([serverId: 'logs', mavenSettings: 'log-settings', nexusRepo: 'logs', zipFilePath: '*.zip'])\n
"},{"location":"libraries/edgeXRelease/","title":"edgeXRelease","text":""},{"location":"libraries/edgeXRelease/#overview","title":"Overview","text":"

Shared library with helper functions to manage releases. This is the main entry point for all automated releases using the \ud83d\udd17 cd-management/release repository.

"},{"location":"libraries/edgeXRelease/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value name true str Name of the repository that is being released. version true str Semver version to be released. releaseName true str The codename of the release. This is usually used by sub release processes for naming. releaseStream true str What branch the release is being generated from. (This has been superseded by commitId) commitId true str Git Commit SHA to tag or branch for the release. repo true str https git repository url. Example: https://github.com/edgexfoundry/<repo>.git"},{"location":"libraries/edgeXRelease/#functions","title":"Functions","text":"
  • edgeXRelease.collectReleaseYamlFiles: Search through a provided file path and find all the release yaml files to process and parses yaml into a Groovy object using the readYaml function. Default file pattern to search for will be: release/*.yaml. This function will also validate what files have changed in the commit using edgex.didChange and will only release what was changed.
  • edgeXRelease.parallelStepFactory: Returns a Closure to execute the release for all release yaml entries found for the specific commit.
  • edgeXRelease.parallelStepFactoryTransform: Transforms release yaml Groovy object into a Groovy Closure containing all the logic needed to perform the release for the specific repository.
  • edgeXRelease.stageArtifact: If release contains binaries rather than docker images, the binaries need to be staged before the release occurs. This function forces a build of the artifact by triggering the job using the build(job: ..) Jenkins function.
  • edgeXRelease.getBuilderImagesFromReleasedImages: Used to determine what static builder image to use when building a LTS C based repository. Below you can see the transformation.
     // Given the release of the following 2 docker images:\nedgeXRelease.getBuilderImagesFromReleasedImages('nexus3.edgexfoundry.org:10004/sample-service-c')\n> nexus3.edgexfoundry.org:10002/sample-service-c-builder-x86_64:jakarta\n\n edgeXRelease.getBuilderImagesFromReleasedImages('nexus3.edgexfoundry.org:10004/sample-service-c-arm64')\n> nexus3.edgexfoundry.org:10002/sample-service-c-builder-arm64:jakarta\n
"},{"location":"libraries/edgeXReleaseDockerImage/","title":"edgeXReleaseDockerImage","text":""},{"location":"libraries/edgeXReleaseDockerImage/#overview","title":"Overview","text":"

Shared library with helper functions to manage docker image releases to Nexus release and DockerHub.

"},{"location":"libraries/edgeXReleaseDockerImage/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value dockerImage true str Determines whether or not to trigger this function. docker true array Array of docker images to release. docker.image true str Docker image that is being release. docker.destination true array Array of destination registries where to release the image to."},{"location":"libraries/edgeXReleaseDockerImage/#functions","title":"Functions","text":"
  • edgeXReleaseDockerImage.getAvaliableTargets: Returns a list of valid release registries.
  • edgeXReleaseDockerImage.isValidReleaseRegistry: Validates registry to ensure we are not pushing images to unknown registries.
  • edgeXReleaseDockerImage.publishDockerImages: Iterates through all release registry targets and pushes images based on validating image exists.
  • edgeXReleaseDockerImage.publishDockerImage: Pulls, re-tags and pushes source image to destination registry.
  • edgeXReleaseDockerImage.validate: Validates release yaml input before any automation is run.
  • edgeXReleaseDockerImage.imageExists: Checks docker registry to see if image exists.
"},{"location":"libraries/edgeXReleaseDockerImage/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseDockerImage/#sample-release-yaml","title":"Sample Release Yaml","text":"
version: 1.1.2\nreleaseStream: main\ndockerImage: true\ndocker:\n- image: nexus3.edgexfoundry.org:10004/sample-service\ndestination:\n- nexus3.edgexfoundry.org:10002/sample-service\n- docker.io/edgexfoundry/sample-service\n- image: nexus3.edgexfoundry.org:10004/sample-service-arm64\ndestination:\n- nexus3.edgexfoundry.org:10002/sample-service-arm64\n- docker.io/edgexfoundry/sample-service-arm64\n
"},{"location":"libraries/edgeXReleaseDockerImage/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseDockerImage(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseDocs/","title":"edgeXReleaseDocs","text":""},{"location":"libraries/edgeXReleaseDocs/#overview","title":"Overview","text":"

Shared library with helper functions to manage documentation releases. Currently used by edgex-docs.

"},{"location":"libraries/edgeXReleaseDocs/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value docs true str Determines whether or not to trigger this function. docsInfo.nextReleaseVersion true str Next release version to add to the documentation. docsInfo.nextReleaseName true str Next release name to add to the documentation. docsInfo.reviewers true str Who to assign the generated PR's to."},{"location":"libraries/edgeXReleaseDocs/#functions","title":"Functions","text":"
  • edgeXReleaseDocs.publishReleaseBranch: Makes release branch related changes in unique branch then commits release branch.
  • edgeXReleaseDocs.publishVersionChangesPR: Makes version file related changes in unique branch then commits and opens PR.
  • edgeXReleaseDocs.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseDocs/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseDocs/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'edgex-docs'\nversion: '2.2.0'\nreleaseName: 'kamakura'\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/edgex-docs.git'\ncommitId: 'c72b16708d6eed9a08be464a432ce22db7d90667'\ngitTag: false\ndockerImages: false\ndocs: true\ndocsInfo:\nnextReleaseVersion: \"2.3.0\"\nnextReleaseName: levski\nreviewers: edgex-docs-committers\n
"},{"location":"libraries/edgeXReleaseDocs/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseDocs(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitHubAssets/","title":"edgeXReleaseGitHubAssets","text":""},{"location":"libraries/edgeXReleaseGitHubAssets/#overview","title":"Overview","text":"

Shared library with helper functions to manage GitHub Releases with attached binaries. This function works in conjunction with the docker image generated from \ud83d\udd17 Create GitHub Release to manage GitHub releases. Currently used by edgex-cli.

"},{"location":"libraries/edgeXReleaseGitHubAssets/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value gitHubRelease true str Determines whether or not to trigger this function. gitHubReleaseAssets true array List of binaries to release along with generated GitHub Release."},{"location":"libraries/edgeXReleaseGitHubAssets/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubAssets.getCredentialsId: Return correct PAT based on ENV.SILO to access GitHub api.
  • edgeXReleaseGitHubAssets.getRepoInfo: Extracts pertinent information from repository and returns as Map.
  • edgeXReleaseGitHubAssets.createGitHubRelease: Wraps call to create-github-release to generate GitHub release.
  • edgeXReleaseGitHubAssets.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseGitHubAssets/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseGitHubAssets/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'sample-service'\nversion: 1.1.2\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/sample-service.git'\ngitHubRelease: true\ngitHubReleaseAssets:\n- 'https://nexus-location/asset1'\n- 'https://nexus-location/asset2'\n- 'https://nexus-location/asset3'\n
"},{"location":"libraries/edgeXReleaseGitHubAssets/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseGitHubAssets(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitTag/","title":"edgeXReleaseGitHubTag","text":""},{"location":"libraries/edgeXReleaseGitTag/#overview","title":"Overview","text":"

Shared library with helper functions to create, sign and bump Git tags.

"},{"location":"libraries/edgeXReleaseGitTag/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value gitTag true str Determines whether or not to trigger this function. semverBumpLevel false str Semver bump level to be used by git-semver. Default: -pre=dev pre"},{"location":"libraries/edgeXReleaseGitTag/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubTag.cloneRepo: Generic function to properly clone a repository to a specific subfolder. Directory name generated from releaseYaml.name.
  • edgeXReleaseGitHubTag.setAndSignGitTag: Sets up release tag using git-semver from the specified version set in releaseYaml.version. NOTE: git-semver force is used here for impotency in case tag already exists. So existing tags will be overridden.
  • edgeXReleaseGitHubTag.bumpAndPushGitTag: Pushes signed tag and optionally bumps next version.
"},{"location":"libraries/edgeXReleaseGitTag/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseGitTag/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'sample-service'\nversion: '1.1.2'\nreleaseStream: 'main'\ncommitId: '0cc1d67607642c9413e4a80d25a2df35ecc76d41'\nrepo: 'https://github.com/edgexfoundry/sample-service.git'\ngitTag: true\nsemverBumpLevel: 'patch' #optional\n
"},{"location":"libraries/edgeXReleaseGitTag/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseGitTag(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseGitTagUtil/","title":"edgeXReleaseGitHubTagUtil","text":""},{"location":"libraries/edgeXReleaseGitTagUtil/#overview","title":"Overview","text":"

Shared library with supporting helper functions to manage Git tags.

"},{"location":"libraries/edgeXReleaseGitTagUtil/#functions","title":"Functions","text":"
  • edgeXReleaseGitHubTagUtil.getSSHRepoName: Converts https repo remote to ssh git@github.com: remote.
  • edgeXReleaseGitHubTagUtil.signGitTag: Wrapper around edgeXInfraLFToolsSign that signs git tag for a release.
  • edgeXReleaseGitHubTagUtil.releaseGitTag: Main function that does full end-to-end git tag release.
  • edgeXReleaseGitHubTagUtil.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseOpenApi/","title":"edgeXReleaseOpenApi","text":""},{"location":"libraries/edgeXReleaseOpenApi/#overview","title":"Overview","text":"

Shared library with helper functions to manage OpenAPI YAML related changes. Currently used by sdk repos.

"},{"location":"libraries/edgeXReleaseOpenApi/#required-yaml","title":"Required Yaml","text":"Name Required Type Description and Default Value apiInfo.nextReleaseVersion true str Next release version to for the OpenAPI yaml files. apiInfo.reviewers true str Who to assign the generated PR to."},{"location":"libraries/edgeXReleaseOpenApi/#functions","title":"Functions","text":"
  • edgeXReleaseOpenApi.publishReleaseBranch: Makes release branch related changes in unique branch then commits release branch.
  • edgeXReleaseOpenApi.publishOpenApiChanges: Makes OpenAPI related changes in unique branch then commits and opens PR.
  • edgeXReleaseOpenApi.validate: Validates release yaml input before any automation is run.
"},{"location":"libraries/edgeXReleaseOpenApi/#usage","title":"Usage","text":""},{"location":"libraries/edgeXReleaseOpenApi/#sample-release-yaml","title":"Sample Release Yaml","text":"
name: 'device-sdk-go'\nversion: '2.2.0'\nreleaseName: 'kamakura'\nreleaseStream: 'main'\nrepo: 'https://github.com/edgexfoundry/device-sdk-go.git'\ncommitId: 'c72b16708d6eed9a08be464a432ce22db7d90667'\ngitTag: true\ndockerImages: false\ngitHubRelease: false\napiInfo: [\nnextReleaseVersion: '2.3.0',\nreviewers: edgexfoundry/edgex-committers\n]\n
"},{"location":"libraries/edgeXReleaseOpenApi/#groovy-call","title":"Groovy Call","text":"
edgeXReleaseOpenApi(releaseYaml)\n
"},{"location":"libraries/edgeXReleaseSnap/","title":"edgeXReleaseSnap","text":"

\u26a0\ufe0f Deprecated... Snaps are no longer published by EdgeX DevOps. They are now managed by the team at Canonical. DO NOT USE \u26a0\ufe0f

"},{"location":"libraries/edgeXSemver/","title":"edgeXSemver","text":""},{"location":"libraries/edgeXSemver/#overview","title":"Overview","text":"

Shared library containing a useful set of functions to help with the creation of semantic versioning using the git-semver python library. The main call function builds the git semver command based on the provided input.

Please note: this shared library is responsible for setting the VERSION environment variable during git semver init execution.

"},{"location":"libraries/edgeXSemver/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value command false str Specify which git semver sub command to run. Example: init, bump, push semverVersion false string Force a specific override version instead of reading the version from the semver branch. Default: <empty string> gitSemverVersion false string What version of the git-semver docker image to use. Default: latest credentials false string Which Jenkins credential to use to authenticate to GitHub and push git tag. Default: edgex-jenkins-ssh"},{"location":"libraries/edgeXSemver/#functions","title":"Functions","text":"
  • edgeXSemver.executeGitSemver: Execute semverCommand via ssh with provided credentials.
  • edgeXSemver.setGitSemverHeadTag: set GITSEMVER_HEAD_TAG to value of HEAD when any of the following conditions are satisfied:
  • An init version is specified and HEAD is tagged with init version.
  • An init version is not specified and HEAD is tagged.
  • edgeXSemver.getCommitTags: Return list of all tags at a specific commit point.
"},{"location":"libraries/edgeXSemver/#usage","title":"Usage","text":"

Regular init

edgeXSemver('init')\n

Force specific the semver version to use.

edgeXSemver('init', '2.0.0')\n

Bump the semver version using default semver bump level (pre-release).

edgeXSemver('bump')\n
"},{"location":"libraries/edgeXSetupEnvironment/","title":"edgeXSetupEnvironment","text":""},{"location":"libraries/edgeXSetupEnvironment/#overview","title":"Overview","text":"

Shared library to setup a build environment given a Map of key value pairs. Some extra environment variables are set to help with the build process including:

  • GIT_BRANCH
  • GIT_COMMIT
  • GIT_BRANCH_CLEAN
  • SHORT_GIT_COMMIT
  • SEMVER_BRANCH
  • SEMVER_PRE_PREFIX
"},{"location":"libraries/edgeXSetupEnvironment/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value vars false str A Map of key/value pairs to expose to the Jenkins environment."},{"location":"libraries/edgeXSetupEnvironment/#usage","title":"Usage","text":"
edgeXSetupEnvironment([ PROJECT: 'edgex-global-pipelines' ])\n...\n...\n// This will expose an environment variable named `PROJECT` with the value `edgex-global-pipelines`\n// as well as the extra environment vars mentioned above.\n
"},{"location":"libraries/edgeXSnap/","title":"edgeXSnap","text":""},{"location":"libraries/edgeXSnap/#overview","title":"Overview","text":"

\u26a0\ufe0f Deprecated Warning... Snaps are no longer being built as part of the Jenkins pipeline. They are being built and tested using GitHub Actions and are managed by the team at Canonical. DO NOT USE \u26a0\ufe0f

Wrapper around resources/snap-build.sh script. No parameters required.

"},{"location":"libraries/edgeXSnap/#usage","title":"Usage","text":"
edgeXSnap()\n
"},{"location":"libraries/edgeXSnyk/","title":"edgeXSnyk","text":""},{"location":"libraries/edgeXSnyk/#overview","title":"Overview","text":"

Shared library containing a useful set of functions to help with the creation of semantic versioning using the git-semver python library. The main call function builds the git semver command based on the provided input.

Please note: this shared library is responsible for setting the VERSION environment variable during git semver init execution.

"},{"location":"libraries/edgeXSnyk/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value command false str Specify which Snyk command to run. Possible values: test, monitor. Default: monitor dockerImage false string If scanning a docker image either a local image name or remote image name. dockerFile false string If scanning a docker image, the path to Dockerfile relative to the Jenkins WORKSPACE. severity false string Severity threshold to mark the build as unstable. sendEmail false string Whether or not to send an email of the findings. Default: true emailTo false string Recipient list of who to send the email to. htmlReport false string Whether or not to generate an HTML report of findings. Default: false"},{"location":"libraries/edgeXSnyk/#usage","title":"Usage","text":"

Test and continuously monitor project dependencies. For Go projects, this is typically the go.mod file:

edgeXSnyk()\n

Test docker image for vulnerabilities and output results to Jenkins console:

edgeXSnyk(\ncommand: 'test',\ndockerImage: 'nexus3.edgexfoundry.org:10004/core-command:latest',\ndockerFile: '<path to Dockerfile>'\n)\n

Test docker image for vulnerabilities and send email of findings:

edgeXSnyk(\ncommand: 'test',\ndockerImage: 'nexus3.edgexfoundry.org:10004/core-command:latest',\ndockerFile: '<path to Dockerfile>',\nseverity: 'high',\nsendEmail: true,\nemailTo: <email address(s)>,\nhtmlReport: true\n)\n
"},{"location":"libraries/edgeXSwaggerPublish/","title":"edgeXSwaggerPublish","text":""},{"location":"libraries/edgeXSwaggerPublish/#overview","title":"Overview","text":"

Shared library containing methods to publish Swagger API docs up to https://api.swaggerhub.com.

NOTE: ${APIKEY} needs to be a pointer to a file with the key. This will need to be set locally from your environment or from Jenkins.

"},{"location":"libraries/edgeXSwaggerPublish/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value owner false str Specify Swagger API owner. Default: EdgeXFoundry1 apiFolders true string Space delimited list of folders to publish. swaggerCredentialId false string Config file Id that contains the Swagger API key to allow publishing of API docs. Default: swaggerhub-api-key"},{"location":"libraries/edgeXSwaggerPublish/#usage","title":"Usage","text":"

Publish single folder to Swagger to owner:EdgeXFoundry1

edgeXSwaggerPublish(apiFolders: 'openapi/v1')\n

Publish multiple API folders to Swagger to owner:EdgeXFoundry1

edgeXSwaggerPublish(apiFolders: 'openapi/v1 openapi/v2')\n

Publish single folder to swagger with a customer owner/organization.

edgeXSwaggerPublish(owner: 'customOwner', apiFolders:'openapi/v1')\n
"},{"location":"libraries/edgeXUpdateNamedTag/","title":"edgeXUpdateNamedTag","text":""},{"location":"libraries/edgeXUpdateNamedTag/#overview","title":"Overview","text":"

Shared library that wraps the resources/update-named-tag.sh script. This script will create a new \"named\" git tag pointing to an existing git tag. This is really useful for creating \"stable\" or \"experimental\" tags that point to another specific versioned git tag. For example, if you wanted to have a \"stable\" tag point to a version tag of \"v1.4.0\" you can run this script to do so. See usage below.

"},{"location":"libraries/edgeXUpdateNamedTag/#parameters","title":"Parameters","text":"Name Required Type Description and Default Value ogVersion true str Original version to create named tag from. namedVersion true str Space delimited list of folders to publish."},{"location":"libraries/edgeXUpdateNamedTag/#usage","title":"Usage","text":"

Create a stable tag pointing to a specific version.

edgeXUpdateNamedTag('v1.2.3', 'stable')\n

Create an experimental tag pointing to a specific version.

edgeXUpdateNamedTag('v2.1.20', 'experimental')\n
"},{"location":"libraries/edgex/","title":"edgex","text":""},{"location":"libraries/edgex/#overview","title":"Overview","text":"

Shared library of common helper functions for all EdgeX Jenkins pipelines.

"},{"location":"libraries/edgex/#functions","title":"Functions","text":"
  • edgex.isReleaseStream: Used to validate whether the current branch that Jenkins is building is a branch that is considered a branch with \"releasable\" artifacts (i.e docker push, git semver push).
  • edgex.isLTS: Used to determine if the current branch that Jenkins is building is for an LTS release.
  • edgex.getTargetBranch: Used to determine the target branch that is being merged into for a PR.
  • edgex.didChange: Determine if the given expression matches the files that changed in a given PR or merge. For example:
    // Did any .go files change from the current branch compared to origin/main\ndidChange('*.go')\n\n// Did any .yaml files change from the current branch compared to origin/release\ndidChange('*.yaml', 'origin/release')\n
  • edgex.mainNode: Given a config map with config.nodes, either return the node label marked as defaultNode = true or return the DevOps managed \"default\" node label.
  • edgex.nodeExists: Verify a given node architecture matches provided architecture.
  • edgex.getNode: Return node with architecture that matches provided architecture.
  • edgex.setupNodes: Setup default node labels for x86_64 and arm64 nodes.
  • edgex.getVmArch: Run uname to determine VM architecture. If aarch64 is returned, convert to the result to arm64.
  • edgex.bannerMessage: Vanity function to wrap given input message with a banner style output for easier readability in Jenkins console.
  • edgex.printMap: Vanity function to print Groovy Map to the Jenkins console.
  • edgex.defaultTrue: Returns true if the input is true or null. This is useful to setup default values in functions when none is provided.
  • edgex.defaultFalse: Returns true if the input is false or null. This is useful to setup default values in functions when none is provided.
  • edgex.releaseInfo: Call shell script resources/releaseinfo.sh to output current edgex-global-pipeline version information in the Jenkins console. This is really useful for debugging older builds in case issues are discovered.
  • edgex.isDryRun: Whether or not the env.DRY_RUN environment variable is set. Will return true if DRY_RUN is set, false otherwise.
  • edgex.isMergeCommit: Determines if the current commit Jenkins is building is considered a git \"merge commit\". Useful if determining parent commit info.
  • edgex.getPreviousCommit: Determines the previous commit SHA given the merge commit or squash commit git use-cases. Different git commands have to be run to be able to determine the previous commit.
  • edgex.getBranchName: Returns the current branch name from git.
  • edgex.getCommitMessage: Returns the current commit message from git given a commit SHA.
  • edgex.isBuildCommit: Return true when the commit message follows the pattern build(...): [semanticVersion,namedTag] ....
  • edgex.parseBuildCommit: Return the parameters for the build [semanticVersion,namedTag].
  • edgex.getTmpDir: Run mktemp with given pattern to create a temporary directory in /tmp.
  • edgex.getGoLangBaseImage: Return DevOps managed base images used in Go pipelines.
  • edgex.isGoProject: Looks at repository directory structure to determine if the repository is Golang based. Uses the existence of the go.mod file.
  • edgex.getCBaseImage: Return the base image used as the base image for all C based repositories.
  • edgex.parallelJobCost: Wraps call to lfParallelCostCapture inside docker image to save time downloading pip dependencies.
  • edgex.patchAlpineSeccompArm64: A fix for arm64 nodes that enables a security profile for docker. Another workaround is to just use the --privileged docker flag.
  • edgex.isLTSReleaseBuild: Returns true if current commit message begins with ci(lts-release).
  • edgex.semverPrep: Poorly named function that sets up the env.NAMED_TAG and env.BUILD_STABLE_DOCKER_IMAGE for the build commit concept. Will be removed in a future release.
  • edgex.waitFor: Useful function to wait for a condition in a shell script to be met.
  • edgex.waitForImages: Useful function to determine if a docker image has been pushed to a repository.
  • edgex.commitChange: Commits a change to the repo with a given message.
  • edgex.createPR: Creates a PR with the GitHub CLI for with a given branch, title, message and reviewers for. Note: This is generic enough to be used in other functions.
"},{"location":"releases/jakarta-lts-initial/","title":"Jakarta LTS Changes","text":""},{"location":"releases/jakarta-lts-initial/#cd-management","title":"cd-management","text":"
  • New release branch in cd-management to manage lts. Maybe call it lts
  • New field in YAML signifying that this is an LTS release:
---\nname: 'edgex-go'\nversion: '2.1.0'\nreleaseName: 'jakarta'\nreleaseStream: 'main'\nlts: true # <-- new field\n...\n
"},{"location":"releases/jakarta-lts-initial/#questions","title":"Questions?","text":"
  • Should we name the lts branch for all repos lts? OR use it's codename like jakarta?

This would trigger a new process in edgex-global-pipelines@edgeXRelease. See changes to edgex-global-pipelines

"},{"location":"releases/jakarta-lts-initial/#ci-build-images","title":"ci-build-images","text":"
  • Branch the golang-1.16 branch to golang-1.16-lts or similar and push the resulting image to the Nexus release repo.
  • Branch the gcc branch to gcc-lts or similar and push the resulting image to the Nexus release repo.

These images should be pretty simple as to push to Nexus release because edgeXBuildDocker allows us to specify the Nexus release repository as a target. See dockerNexusRepo in the docs.

"},{"location":"releases/jakarta-lts-initial/#edgex-compose","title":"edgex-compose","text":"

3rd party docker images should be archive to the Nexus release repository. Images that should be archived are:

consul kong lfedge/ekuiper postgres redis vault

A modification to the Jenkinsfile can be make to introduce a new pipeline parameter to trigger a stage that gathers the existing 3rd party images, retags and pushes them to the Nexus release repository.

Sample script to extract and retag:

for image in $(grep \"image:\" ./docker-compose.yml | grep -v nexus | awk '{print $2}' | sort); do echo docker tag $image nexus3.edgexfoundry.org:10002/3rdparty/$image; echo docker push nexus3.edgexfoundry.org:10002/3rdparty/$image; done\n
"},{"location":"releases/jakarta-lts-initial/#edgex-global-pipelinesedgexrelease","title":"edgex-global-pipelines@edgeXRelease","text":"

Various changes will be needed in vars/edgexRelease.groovy to support the lts release. See https://github.com/edgexfoundry/edgex-global-pipelines/blob/main/vars/edgeXRelease.groovy#L38. If we are doing an LTS release we should not create a tag, we need to create a long running branch where changes can be made without affecting the main branch.

"},{"location":"releases/jakarta-lts-initial/#changes-for-go-repositories","title":"Changes For Go Repositories","text":"

As called out in the LTS release process, for Go based projects, we will switch to Go vendoring for dependencies. This will give us 100% confidence that the dependencies will always be available in the LTS release and allow for easy patching and rebuilding.

  • If the release is an LTS release and the LTS branch does not exist, we will need to run something similar to the following:
git checkout -b <lts-release-name>\ngrep -v vendor .gitignore > .gitignore.tmp\nmv .gitignore.tmp .gitignore\nmake vendor\ngit add .\ngit commit -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
  • If the release is an LTS release and the LTS branch does exist, we will need to run something similar to the following:
git checkout <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
"},{"location":"releases/jakarta-lts-initial/#changes-for-c-repositories","title":"Changes For C Repositories","text":"

There is no dependency management for C based projects, so no dependency management changes are needed. We will need to branch and push though.

  • If the release is an LTS release and the LTS branch does not exist, we will need to run something similar to the following:
git checkout -b <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
  • If the release is an LTS release and the LTS branch does exist, we will need to run something similar to the following:
git checkout <lts-release-name>\ngit commit --allow-empty -m \"ci(lts-release): LTS release v<VERSION> @<commitId from release yaml>\"\ngit push origin <lts-release-name>\n
"},{"location":"releases/jakarta-lts-initial/#edgex-global-pipelines-general-changes","title":"edgex-global-pipelines General Changes","text":""},{"location":"releases/jakarta-lts-initial/#semver-notes-and-noop-builds","title":"Semver notes and noop builds","text":"
  • Git semver will continue to be used for lts releases. After the initial release a pre-release dev tag will be created as usual. However, we have to introduce the concept of a noop (no operation) build due to the fact we are branching and tagging. We can use the commit message as a way to determine a noop build. The flow will go something like this:

    1. 1st build, triggered by push of lts branch to GitHub: No op, no semver needed
    2. edgeXRelease creates force creates tag 2.1.0
    3. 2nd build, triggered by edgeXRelease and builds the 2.1.0 code and pushes the release to Nexus
    4. Bump semver to 2.1.1-dev.1
  • vars/edgex.groovy

  • Potentially need to add a new method similar to isReleaseStream() called isLTS().
  • Add method or modify getGoLangBaseImage() to return the proper released ci-build-image if this is an LTS release
  • vars/edgeXBuildGoApp.groovy
  • For LTS releases we need to use the released CI base build image referenced in the ci-build-images section. So we will need to modify this method prepBaseBuildImage() to return the proper base build image if the release is an LTS release. Will call edgex function above.
  • vars/edgeXBuildGoParallel.groovy
  • For LTS releases we need to use the released CI base build image referenced in the ci-build-images section. So we will need to modify this method prepBaseBuildImage() to return the proper base build image if the release is an LTS release. Will call edgex function above.
  • vars/edgeXBuildCApp.groovy
  • This will be the most complicated change. We will need to release/archive the build images created from the Dockerfile.build. These images will need to be pushed to nexus release and then used as the base images for all subsequent LTS builds. This will ensure we have 100% reproducibility of the C repositories. For example we will need to create a device-coap-c specific docker image will all build dependencies archived in the image.
  • A new stage will need to be added to the pipeline to release the docker build images. This stage can either be triggered by a new parameter to the pipeline, or can potentially be triggered by a special commit message. Since we are already doing a special commit message for the initial push, the commit message may be the correct approach.
  • Changes will be required to the prepBaseBuildImage() function, to use repo level build images if we are on an LTS branch.
"},{"location":"releases/jakarta-release-stages/","title":"Jakarta Release Stages","text":""},{"location":"releases/jakarta-release-stages/#release-architecture","title":"Release Architecture","text":""},{"location":"releases/jakarta-release-stages/#pre-lts-flow","title":"Pre-LTS Flow","text":""},{"location":"releases/jakarta-release-stages/#post-lts-flow","title":"Post-LTS Flow","text":""},{"location":"releases/jakarta-release-stages/#c-based-services","title":"C Based Services","text":""},{"location":"releases/jakarta-release-stages/#release-flow","title":"Release Flow","text":"
  • \ud83c\udd95 edgeXRelease: creates and pushes \"jakarta\" branch at specific git sha
  • The push of the tag triggers new LTSRelease build
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/lts-test/19/pipeline/81
  • \"LTS Release Build\", builds project specific relevant ci build images (x86_64, arm64) will all dependencies bundled
  • Images are pushed to nexus release, i.e. nexus3.edgexfoundry.org:10002/device-coap-c-builder-{ARCH}:{GIT SHA}
  • [Existing] edgeXRelease: tags git sha with release version e.g. 2.1.0
  • [Existing] edgeXRelease: stages build artifact, i.e. triggers device-coap-c/jakarta job
  • \ud83c\udd95 If this is a C build and LTS we will need to wait until the first LTSRelease build is done before running this build. New function edgex.waitForImages is used to wait until builder images are ready.
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/lts-test/20/pipeline/154
  • [Existing] edgeXRelease: Bump Semver, i.e. next dev tag 2.1.1-dev.1
"},{"location":"releases/jakarta-release-stages/#pr-fixes-regular-dev-process","title":"PR Fixes (Regular Dev Process)","text":"

PR is open in fork as normal, but target branch will be LTS (jakarta) branch

  • [Existing] User open's PR as normal for fix, etc https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/PR-27/7/pipeline/213
  • \ud83c\udd95 Pipeline will detect the merge target is an LTS branch and will use released ci build image from the release process rather than build a ci image on the fly
  • prepBaseBuildImage() was the perfect abstraction to do this!

    docker pull nexus3.edgexfoundry.org:10002/device-coap-c-builder-x86_64:{GIT SHA}\ndocker tag nexus3.edgexfoundry.org:10002/device-coap-c-builder-x86_64:{GIT SHA} ci-base-image-x86_64\n
    docker pull nexus3.edgexfoundry.org:10002/device-coap-c-builder-arm64:{GIT SHA}\ndocker tag nexus3.edgexfoundry.org:10002/device-coap-c-builder-arm64:{GIT SHA} ci-base-image-arm64\n
"},{"location":"releases/jakarta-release-stages/#main-branch-regular-dev-process","title":"Main Branch (Regular Dev Process)","text":"

PR open against the main branch, no regressions introduced: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fdevice-coap-c/detail/PR-29/2/pipeline

"},{"location":"releases/jakarta-release-stages/#go-based-services","title":"Go based services","text":""},{"location":"releases/jakarta-release-stages/#release-flow_1","title":"Release Flow","text":"
  • \ud83c\udd95 edgeXRelease: creates and pushes \"jakarta\" branch at specific git sha
  • The push of the tag triggers new LTSRelease build
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/lts-test/24/pipeline
  • \"LTS Release Build\" will be a no op build in the case of Golang
  • [Existing] edgeXRelease: tags git sha with release version e.g. 2.1.0
  • [Existing] edgeXRelease: stages build artifact, i.e. triggers sample-service/jakarta job
  • \ud83c\udd95 No wait needed as of yet, but maybe will need something in the future
  • Job: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/lts-test/25/pipeline/147 (need to add lts branches to isReleaseStream)
  • [Existing] edgeXRelease: Bump Semver, i.e. next dev tag 2.1.1-dev.1
"},{"location":"releases/jakarta-release-stages/#pr-fixes-regular-dev-process_1","title":"PR Fixes (Regular Dev Process)","text":"

PR is open in fork as normal, but target branch will be LTS (jakarta) branch

  • [Existing] User open's PR as normal for fix, etc https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/PR-135/9/pipeline
  • \ud83c\udd95 getGolangBaseImage will return Go LTS image that DevOps manually releases into Nexus release

    docker build -t ci-base-image-x86_64 -f Dockerfile --build-arg BASE=nexus3.edgexfoundry.org:10002/edgex-devops/edgex-golang-base:1.16-alpine-lts --build-arg 'MAKE=echo noop' --target=builder .\n
    docker build -t ci-base-image-arm64 -f Dockerfile --build-arg BASE=nexus3.edgexfoundry.org:10002/edgex-devops/edgex-golang-base-arm64:1.16-alpine-lts --build-arg MAKE=\"echo noop\" --target=builder .\n
"},{"location":"releases/jakarta-release-stages/#main-branch-regular-dev-process_1","title":"Main branch (Regular Dev Process)","text":"

PR open against the main branch, no regressions introduced: https://jenkins.edgexfoundry.org/blue/organizations/jenkins/edgexfoundry%2Fsample-service/detail/PR-136/1/pipeline

"},{"location":"tutorials/","title":"Tutorials","text":"

More coming soon!

  • Manual Version Bump
  • Pull Request Sandbox Testing
"},{"location":"tutorials/docker-build-strategy/","title":"Docker Build Strategy","text":"

Docker is a great tool for the CI/CD ecosystem. As the EdgeX DevOps community, we made the decision early when designing the EdgeX Jenkins pipelines to make Docker the center of our build strategy. The advantage of using Docker as the build context is that it allows for creating reproducible builds from Jenkins to our local build environment. Thus creating a portable build environment and minimizing build errors between environments. The EdgeX Jenkins pipelines use Docker images as the context for any build. This Docker image is generated from the Dockerfile.build found at the root of every EdgeX repository. Any dependencies or packages required for testing or compilation needs to be added to the Dockerfile.build file.

"},{"location":"tutorials/docker-build-strategy/#local-testing","title":"Local Testing","text":"

If we want to test how the build will run on Jenkins we can follow these steps locally.

"},{"location":"tutorials/docker-build-strategy/#example","title":"Example","text":"

First we build the \"build image\" edgex-ci-build-image

cd app-service-configurable\ndocker build -t edgex-ci-build-image -f Dockerfile.build\n

Now we run the build image with some make targets and bind mount our current directory to a folder called /ws (workspace)

docker run --rm -v $(pwd):/ws -w /ws edgex-ci-build-image sh -c 'make test build'\n

Or to put it into a convenient one-liner:

cd app-service-configurable\ndocker build -t edgex-ci-build-image -f Dockerfile.build . && docker run --rm -v $(pwd):/ws -w /ws edgex-ci-build-image sh -c 'make test build'\n
Sending build context to Docker daemon    127kB\nStep 1/8 : ARG BASE=golang:1.15-alpine\nStep 2/8 : FROM ${BASE}\n ---> 1a87ceb1ace5\nStep 3/8 : LABEL license='SPDX-License-Identifier: Apache-2.0'   copyright='Copyright (c) 2019: Intel'\n ---> Using cache\n ---> 9f1aa172c1d7\nStep 4/8 : RUN sed -e 's/dl-cdn[.]alpinelinux.org/nl.alpinelinux.org/g' -i~ /etc/apk/repositories\n ---> Using cache\n ---> fec4da09e9ec\nStep 5/8 : RUN apk add --no-cache make git gcc libc-dev libsodium-dev zeromq-dev bash\n...\nSuccessfully built ce2be0b9fe31\nSuccessfully tagged edgex-ci-build-image:latest\nCGO_ENABLED=1 go test -coverprofile=coverage.out ./...\n?   github.com/edgexfoundry/app-service-configurable\n    [no test files]\nCGO_ENABLED=1 go build -ldflags \"-X github.com/edgexfoundry/app-functions-sdk-go/internal.SDKVersion=v1.2.1-dev.35 -X github.com/edgexfoundry/app-functions-sdk-go/internal.ApplicationVersion=0.0.0\" app-service-configurable\n
"},{"location":"tutorials/docker-build-strategy/#tooling-caveats","title":"Tooling Caveats","text":"

Docker build images are Alpine based to save on disk space and bandwith and with that comes potential tooling incompatiblities. For example a number of pre-installed base packages on Alpine are the BusyBox versions of the tools. BusyBox versions can sometimes have different arguments than their GNU counterparts. For instance the tar command:

"},{"location":"tutorials/docker-build-strategy/#busybox-alpine","title":"BusyBox (Alpine)","text":"
$ tar --help\nBusyBox v1.31.1 () multi-call binary.\n\nUsage: tar c|x|t [-ZzJjahmvokO] [-f TARFILE] [-C DIR] [-T FILE] [-X FILE] [--exclude PATTERN]... [FILE]...\n
"},{"location":"tutorials/docker-build-strategy/#gnu-other-linux-distros","title":"GNU (Other linux distros)","text":"
$ tar --help\nUsage: tar [OPTION...] [FILE]...\nGNU 'tar' saves many files together into a single tape or disk archive, and can\nrestore individual files from the archive.\n

This can lead to unexpected issues if say, for instance, you are depending on a specific flag provided by the tool. One option to fix this is to just use the BusyBox flags, however this may break when not running inside the Docker build image. Another option is to find the alternative package and install that version. For example, Alpine provides the GNU alternative tar binary under the tar Alpine package:

$ apk add --update tar\n$ tar --help\nUsage: tar [OPTION...] [FILE]...\nGNU 'tar' saves many files together into a single tape or disk archive, and can\nrestore individual files from the archive.\n
"},{"location":"tutorials/docker-build-strategy/#the-jenkins-way","title":"The Jenkins Way","text":"

The above example is similar to how Jenkins runs the build with a few distinctions. First, the make test and make build commands are broken up into two stages. This is an important distinction because it allows for a more granular pipeline allowing for better error handling. The other distinction is that Jenkins takes advantage of a caching base layer image that is passed in at build time. Take a look at the Dockerfile.build. You will notice the BASE docker ARG at the top of the file.

ARG BASE=golang:1.15-alpine\nFROM ${BASE}\n...\n

This allows Jenkins to override the base image during the build with an image from Nexus helping to alleviate issues with DockerHub pull limits as well as random Docker pull failures. On Jenkins this happens in the Prep stage:

docker build -t ci-base-image-x86_64 \\\n-f Dockerfile.build \\\n--build-arg BASE=nexus3.edgexfoundry.org:10003/edgex-devops/edgex-golang-base:1.15-alpine \\\n.\n

The DevOps WG team manages these Golang base images and the Dockerfile for the latest Golang image used can be found here: https://github.com/edgexfoundry/ci-build-images/tree/golang-1.15. This cache image contains most of the dependencies used in the majority of the pipelines allowing us to cache dependencies at the base image level and increasing builds speeds.

After the base image is built the test and build stages run in a similar manner to the local testing scenario:

docker run -t -u 0:0 \\\n  -w /w/workspace/app-service-configurable/60 \\\n  -v /w/workspace/app-service-configurable/60:/w/workspace/app-service-configurable/60:rw,z \\\n  -v /w/workspace/app-service-configurable/60@tmp:/w/workspace/app-service-configurable/60@tmp:rw,z \\\n  ci-base-image-x86_64 ... make test\n
"},{"location":"tutorials/docker-build-strategy/#next-steps","title":"Next steps","text":"

More information can be found by reading the documentation or source code of these pipelines:

  • edgeXBuildGoApp source
  • edgeXBuildGoParallel source
"},{"location":"tutorials/manual-bump/","title":"Manual Version Bump Process","text":"

Sometimes the version of the edgex-global-pipelines needs to be changed between stable and experimental tags in order to enhance and validate that the changes work as expected.

The process documented here outlines the manual process for bumping the version and tag on the global libraries.

"},{"location":"tutorials/manual-bump/#committer-access-required","title":"Committer Access Required","text":"

You must have write access to the repo to perform this manual version bump process. - Developer must be a member of the devops-core-team as per TSC approval - Version info can be obtained through view of the Jenkins Pipeline log for last successful build

$ git clone git@github.com:edgexfoundry/edgex-global-pipelines.git\n$ cd edgex-global-pipelines\n$ ./resources/update-named-tag.sh <version> <stable|experimental>\n
"},{"location":"tutorials/manual-bump/#click-on-image-below-to-view-ascii-recording-of-the-manual-version-bump-process","title":"Click on image below to view ASCII recording of the manual version bump process","text":""},{"location":"tutorials/pr-commit-for-testing/","title":"Pull Request Sandbox Testing","text":""},{"location":"tutorials/pr-commit-for-testing/#introduction","title":"Introduction","text":"

The EdgeX Jenkins Production Server and EdgeX Jenkins Sandbox Server are configured to use the edgex-global-pipelines library. The servers target either stable or experimental tags for Production and Sandbox servers respectively.

To make functional testing of Jenkins Shared Pipeline Libraries more convenient, you can use a commit hash from a Pull Request into edgex-global-pipelines to override the default pipeline version that the Jenkins server is using. (stable/experimental)

"},{"location":"tutorials/pr-commit-for-testing/#step-1-create-draft-pr","title":"Step 1 - Create Draft PR","text":"

When you have changes you'd like to functionally test, open a Draft Pull Request from your forked repository of edgex-global-pipelines into edgex-global-pipelines:main

Make clear that this is a PR for functional testing purposes and is not meant to be merged.

"},{"location":"tutorials/pr-commit-for-testing/#step-2-use-pr-commit-hash","title":"Step 2 - Use PR Commit Hash","text":"

Find the commit hash of your draft PR.

Place the commit hash into your Jenkinsfile that is under test. The EdgeX Sample-Service is a good place to functionally test shared libraries without affecting production code.

Add the commit hash after the '@' in the explicit library import statement as shown below.

@Library(\"edgex-global-pipelines@7eba319\") _\n\nedgeXBuildGoApp (\nproject: 'sample-service',\n    goVersion: '1.15',\n    buildExperimentalDockerImage: true\n)\n
"},{"location":"tutorials/pr-commit-for-testing/#step-3-execute-jenkinsfile","title":"Step 3 - Execute Jenkinsfile","text":"

When you execute your functional test build job on the sandbox, the commit hash of your PR will be shown as the commit used for the edgex-global-pipeline shared library. You will see a message similar to the following in your build job console output.

...\nLoading library edgex-global-pipelines@7eba319\nAttempting to resolve 7eba319 from remote references...\n...\n
"},{"location":"tutorials/pr-commit-for-testing/#step-4-finishing-up","title":"Step 4 - Finishing Up","text":"

When you are satisfied that the content of your edgex-global-pipelines fork is functionally tested and ready to be merged, you can convert your draft PR into a real PR and add the appropriate reviewers.

After your PR is merged to main, the experimental tag will point to your newest content. You might want to test your new code by switching back to the experimental tag in your Jenkinsfile.

@Library(\"edgex-global-pipelines@experimental\") _\n

Please clean up and close your PR after you have finished your functional testing.

"},{"location":"tutorials/unit-testing-best-practices/","title":"Unit Testing Best Practices","text":""},{"location":"tutorials/unit-testing-best-practices/#table-of-contents","title":"Table Of Contents","text":"
  • Unit Testing Declarative Pipelines
  • Encapsulate Pipeline logic within Groovy functions
  • Example
  • Mocking Jenkins Dependencies
  • Add plugin dependency to Gradle
  • Mocking Environment Variables
  • Testing environment variables
  • Mock external shared library methods
  • Integration Testing
  • Mock errors
  • Mock external shared library methods
  • Call Graph Example
  • References
"},{"location":"tutorials/unit-testing-best-practices/#unit-testing-declarative-pipelines","title":"Unit Testing Declarative Pipelines","text":"

The edgex-global-pipelines shared library leverages the Jenkins Spock framework for unit testing Jenkins pipeline scripts and functions. The Jenkins Spock unit test framework does not currently support unit testing of Jenkins Declarative Pipeline code.

"},{"location":"tutorials/unit-testing-best-practices/#encapsulate-pipeline-logic-within-groovy-functions","title":"Encapsulate Pipeline logic within Groovy functions","text":"

In order to facilitate unit testing of the edgex-global-pipelines shared library, the DevOps team has made a deliberate effort to to minimize the amount of scripting logic contained within Jenkins declarative pipelines. This is accomplished by encapsulating pipeline logic within a Groovy function and calling the function in the declarative pipeline step as needed. Localizing pipeline logic within Groovy functions enables the Jenkins Spock framework to provide greater test coverage of Pipeline logic.

"},{"location":"tutorials/unit-testing-best-practices/#example","title":"Example","text":"

An example this approach can be seen within the Build -> amd64 -> Prep stage of the edgeXBuildCApp Delcarative Pipeline. Note the logic for prepping the base build image is encapsulated into a method named prepBaseBuildImage and it is called within the declarative Pipeline. Also the prepBaseBuildImage function logic is thoroughly unit tested in the edgeXBuildCApp Spec

"},{"location":"tutorials/unit-testing-best-practices/#mocking-jenkins-dependencies","title":"Mocking Jenkins Dependencies","text":"

Always leverage the builtin capabilities of the Jenkins-Spock framework for mocking Jenkins plugins. For example, if you come across the following error when unit testing your code:

java.lang.IllegalStateException: During a test, the pipeline step [stepName] was called but there was no mock for it.\n
The error above denotes that the code under test calls a pipeline step stepName but there is no mock for it. You are able to explicitly mock the pipeline step using explictlyMockPipelineStep method available in the Jenkins-Spock framework. However it is recommended that the plugin that contains the corresponding step be added as a dependency in the build.gradle file. For instructions on how to do this, refer to the Add plugin dependency to Gradle section.

"},{"location":"tutorials/unit-testing-best-practices/#add-plugin-dependency-to-gradle","title":"Add plugin dependency to Gradle","text":"
  1. Note the name of the Pipeline Step to add.
  2. Go to Pipeline Steps Reference page.
  3. Use your browser and search for the Pipeline Step within the page.
  4. If the Pipeline Step is found, click on the Pipeline that it belongs to, the page for the respective Pipeline should open.
  5. Under the heading click on the View this plugin on the Plugins site link, the plugins.jenkins.io page should open.
  6. In the plugins.jenkins.io page note the ID for the Pipeline. You will use this ID in the next step.
  7. Go to Maven Repository page.
  8. Enter the ID in the search, and locate the result from the results displayed, click on the respective link.
  9. In the page, click on the Jenkins Releases tab.
  10. If you know the version then click it, otherwise click on the latest version that is listed.
  11. In the Gradle tab, note the group, name and version.
  12. Edit the build.gradle file, add the dependency found above to the dependencies section.
"},{"location":"tutorials/unit-testing-best-practices/#mocking-environment-variables","title":"Mocking Environment Variables","text":"

Always ensure the source code under test uses one of the following idioms for getting or setting Environment Variables, doing this will simplify the ability to mock environment variables in the unit test: - Getting the value of an environment variable - env.VARIABLE - env[VARIABLE] - \"${env.VARIABLE}\" - Setting the value of an environment variable - env.VARIABLE = VALUE - env[VARIABLE] = VALUE

"},{"location":"tutorials/unit-testing-best-practices/#testing-environment-variables","title":"Testing environment variables","text":"

Within your unit tests, environment variables are set using the .getBinding().setVariable('name', 'value') idiom. Where the name is env and the value is a map you define within your unit test. The map should define all environment variables the code under test expects, likewise the map can be used to assert any environment variables that the code under test sets.

A good example of this practice is the EdgeXSetupEnvironmentSpec

"},{"location":"tutorials/unit-testing-best-practices/#mock-external-shared-library-methods","title":"Mock external shared library methods","text":"

The edgex-global-pipelines Jenkins shared library consists of multiple scripts exposing methods for various functional areas, where each script is named after the particular functional area it serves. The shared library includes a EdgeX script that serves as utility script containing methods that are shared amongst other scripts. It is common practice for a method in one script call a method in another script, to mock the interaction you use the explictlyMockPipelineVariable to mock the script, then getPipelineMock method to verify the interaction or stub it if necessary.

Mock the external script named script:

explictlyMockPipelineVariable('script')\n
It is recommended to mock all external scripts called within the script under test in the Test Spec setup.

Get the script mock and stub the call to method to return 'value' for any argument passed in:

getPipelineMock('script.method').call(_) >> 'value'\n

"},{"location":"tutorials/unit-testing-best-practices/#integration-testing","title":"Integration Testing","text":"

Integration Testing is defined as a type of testing where software modules are integrated logically and tested as a group. The Jenkins-Spock framework provides the ability to load any number of scripts to test within a given Spec Test. There are instances where performing integration tests is more practical, if you wish to do so then we recommend naming the Spec Test with Int as to differentiate between unit and integration tests.

A good example of this practice is the EdgeXReleaseDockerImageIntSpec

"},{"location":"tutorials/unit-testing-best-practices/#mock-errors","title":"Mock errors","text":"

Always leverage error when wanting to conditionally terminate part of your script. Error is a Pipeline Step whose plugin has been added as a dependency to our project thus is already mocked by the framework. An example showing how you can assert that an error is thrown with a specific message:

1 * getPipelineMock('error').call('error message')\n

"},{"location":"tutorials/unit-testing-best-practices/#mock-external-shared-library-methods_1","title":"Mock external shared library methods","text":"

The difficulties of mocking functions within the same script under test have been described in the following issue: Issue 78. Due to the nature of how the scripts that comprise the edgex-global-pipelines shared library are written; where a deliberate intent is made to develop small, functionally cohesive methods that contribute to a single well-defined task. This development intent results in having scripts with multi-layered call graphs, where methods may call multiple methods from within the same script. We find that the workaround provided in the issue is complicated and doesn't scale well in our environment. For these reasons the method outlined below is being suggested.

  1. For the script under test, document its call graph. A call graph is a control flow graph, which represents calling relationships between methods in a script or program. Each node represents a method and each edge (f, g) indicates that method f calls method g. An example EdgeXReleaseGitTag call graph is depicted below.
  2. Create a second script with the same name as the original script with the word Util added to the end, for example EdgeXReleaseGitTagUtil.groovy.
  3. Analyze the call graph, methods that reside in odd numbered layers should continue to reside in the first script, methods at even numbered layers should be moved from the first script into the second script.
  4. Create a Spec Test for both scripts.

Mocking of methods between both scripts follow the same pattern described for Mock external shared library methods. The only difference with this approach is that the scripts are (for the lack of a better word) name spaced for the respective functional area.

"},{"location":"tutorials/unit-testing-best-practices/#call-graph-example","title":"Call Graph Example","text":"

NOTE The approach outlined above is not recommended as the standard development approach, but as an alternative to re-writing the script under test if mocking of the internal method calls becomes unwieldy.

"},{"location":"tutorials/unit-testing-best-practices/#references","title":"References","text":"
  • Jenkins Spock Documentation
  • Spock Framework Reference
  • Jenkins Shared Libraries
"}]} \ No newline at end of file diff --git a/html/sitemap.xml b/html/sitemap.xml index 3edaa841..38db03d2 100644 --- a/html/sitemap.xml +++ b/html/sitemap.xml @@ -2,207 +2,207 @@ https://edgexfoundry.github.io/edgex-global-pipelines/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXBuildCApp/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXBuildDocker/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXBuildGoApp/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXBuildGoMod/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXBuildGoParallel/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXClair/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXCodecov/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXDocker/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXDockerLogin/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXEmail/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXEmailUtil/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXGHPagesPublish/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXGeneric/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXInfraLFToolsSign/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXInfraPublish/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXInfraShipLogs/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXLTS/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXNexusPublish/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXRelease/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseDockerImage/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseDocs/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseGitHubAssets/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseGitTag/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseGitTagUtil/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseOpenApi/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXReleaseSnap/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXSemver/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXSetupEnvironment/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXSnap/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXSnyk/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXSwaggerPublish/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgeXUpdateNamedTag/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/libraries/edgex/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/releases/jakarta-lts-initial/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/releases/jakarta-release-stages/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/tutorials/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/tutorials/docker-build-strategy/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/tutorials/manual-bump/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/tutorials/pr-commit-for-testing/ - 2023-06-01 + 2023-08-04 daily https://edgexfoundry.github.io/edgex-global-pipelines/tutorials/unit-testing-best-practices/ - 2023-06-01 + 2023-08-04 daily \ No newline at end of file diff --git a/html/sitemap.xml.gz b/html/sitemap.xml.gz index 7585f321..c7ed9ffd 100644 Binary files a/html/sitemap.xml.gz and b/html/sitemap.xml.gz differ diff --git a/html/tutorials/docker-build-strategy/index.html b/html/tutorials/docker-build-strategy/index.html index 0578cd0f..ec1cc7f5 100644 --- a/html/tutorials/docker-build-strategy/index.html +++ b/html/tutorials/docker-build-strategy/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1359,10 +1359,10 @@

Next steps

- + - + diff --git a/html/tutorials/index.html b/html/tutorials/index.html index 80e2ec2e..0eb64729 100644 --- a/html/tutorials/index.html +++ b/html/tutorials/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1129,10 +1129,10 @@

Tutorials

- + - + diff --git a/html/tutorials/manual-bump/index.html b/html/tutorials/manual-bump/index.html index 08b66447..013c3dc1 100644 --- a/html/tutorials/manual-bump/index.html +++ b/html/tutorials/manual-bump/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1196,10 +1196,10 @@

- + - + diff --git a/html/tutorials/pr-commit-for-testing/index.html b/html/tutorials/pr-commit-for-testing/index.html index 1b5a1276..dd2fc870 100644 --- a/html/tutorials/pr-commit-for-testing/index.html +++ b/html/tutorials/pr-commit-for-testing/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1271,10 +1271,10 @@

Step 4 - Finishing Up

- + - + diff --git a/html/tutorials/unit-testing-best-practices/index.html b/html/tutorials/unit-testing-best-practices/index.html index 0da40ca5..90952bed 100644 --- a/html/tutorials/unit-testing-best-practices/index.html +++ b/html/tutorials/unit-testing-best-practices/index.html @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -1212,10 +1212,10 @@

References

- + - +