@spinnaker/docker 2025.4.0-rc1 → 2025.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2 +1,1570 @@
1
- import{REST as e,RetryService as t,AccountService as a,ValidationMessage as s,HelpField as i,Tooltip as n,SETTINGS as o,Registry as r,BakeExecutionLabel as l,AuthenticationService as c,BakeryReader as g,TetheredSelect as m,Spinner as p}from"@spinnaker/core";import d,{groupBy as u,reduce as h,uniq as f,trim as v,get as y}from"lodash";import E from"react";import b from"react-select";import{module as N}from"angular";import I from"@uirouter/angularjs";import{$q as k}from"ngimport";import{Subject as C,from as z}from"rxjs";import{debounceTime as _,switchMap as w}from"rxjs/operators";class L{static getImage(t,a,s){return e("/images").path(s,a,t).query({provider:"docker"}).get().then((e=>e&&e.length?e[0]:null)).catch((()=>null))}static findImages(a){return t.buildRetrySequence((()=>e("/images/find").query(a).get()),(e=>e.length>0),10,1e3).then((e=>e)).catch((()=>[]))}static findTags(a){return t.buildRetrySequence((()=>e("/images/tags").query(a).get()),(e=>e.length>0),10,1e3).then((e=>e)).catch((()=>[]))}}class M{static getImage(t,a,s){return e("/charts").path(s,a,t).query({provider:"docker"}).get().then((e=>e&&e.length?e[0]:null)).catch((()=>null))}static findImages(a){return t.buildRetrySequence((()=>e("/charts/find").query(a).get()),(e=>e.length>0),10,1e3).then((e=>e)).catch((()=>[]))}static findTags(a){return t.buildRetrySequence((()=>e("/charts/tags").query(a).get()),(e=>e.length>0),10,1e3).then((e=>e)).catch((()=>[]))}}class R{static splitImageId(e=""){let t;t=e.includes("@")?e.split("@"):e.split(":");const a=t[0],s=a.split("/").slice(0,-1).join("/"),i=t.length>1?t.slice(1).join(":"):"";let n,o;return i&&(i.startsWith("sha256:")?o=i:n=i),{organization:s,repository:a,digest:o,tag:n}}static generateImageId(e){if(!e.repository||!e.digest&&!e.tag)return;let t;return t=e.digest?`${e.repository}@${e.digest}`:`${e.repository}:${e.tag}`,t}}const x=["organization","repository","tag","digest"],T=[{label:"Manually",value:!0},{label:"Select from list",value:!1}];class S extends E.Component{constructor(e){super(e),this.unmounted=!1,this.cachedValues={},this.handleRefreshImages=()=>{this.refreshImages(this.props)},this.lookupTypeChanged=e=>{const t=e.value,a=this.state.lookupType,s=this.props[a],i=this.cachedValues[t];this.valueChanged(a,void 0),this.cachedValues[t]&&this.valueChanged(t,i),this.setState({lookupType:t}),this.cachedValues[a]=s},this.showManualInput=e=>{if(!e){const e=R.splitImageId(this.props.imageId||"");this.props.onChange(e),this.state.switchedManualWarning&&this.setState({switchedManualWarning:void 0,missingFields:void 0})}this.setState({defineManually:e})};const t=e.account?[{label:e.account,value:e.account}]:[],a=e.organization&&e.organization.length?[{label:e.organization,value:e.organization}]:[],s=e.repository&&e.repository.length?[{label:e.repository,value:e.repository}]:[],i=e.tag&&e.tag.length?[{label:e.tag,value:e.tag}]:[],n=R.splitImageId(e.imageId),o=e.allowManualDefinition&&Boolean(e.imageId&&e.imageId.includes("${"));this.state={accountOptions:t,switchedManualWarning:void 0,imagesLoaded:!1,imagesLoading:!1,organizationOptions:a,repositoryOptions:s,defineManually:o,tagOptions:i,lookupType:e.digest||n.digest?"digest":"tag"}}getAccountMap(e){const t=u(e.filter((e=>e.account)),"account");return h(t,((e,t,a)=>(e[a]=f(t.map((e=>`${e.repository.split("/").slice(0,-1).join("/")}`))),e)),{})}getRegistryMap(e){return e.reduce(((e,t)=>(e[t.account]=t.registry,e)),{})}getOrganizationMap(e){const t=u(e.filter((e=>e.repository)),(e=>`${e.account}/${e.repository.split("/").slice(0,-1).join("/")}`));return h(t,((e,t,a)=>(e[a]=f(t.map((e=>e.repository))),e)),{})}getRepositoryMap(e){const t=u(e.filter((e=>e.account)),"repository");return h(t,((e,t,a)=>(e[a]=f(t.map((e=>e.tag))),e)),{})}getOrganizationsList(e){return e&&e[this.props.showRegistry?this.props.account:this.props.registry]||[]}getRepositoryList(e,t,a){if(e){return e[`${this.props.showRegistry?this.props.account:a}/${t||""}`]||[]}return[]}getTags(e,t,a){let s=[];return this.props.specifyTagByRegex?e&&""===v(e)&&(e=void 0):t&&(s=t[a]||[],s.includes(e)||!e||e.includes("${")||(e=void 0)),{tag:e,tags:s}}componentWillReceiveProps(e){!this.images||["account","showRegistry"].some((t=>this.props[t]!==e[t]))?this.refreshImages(e):["organization","registry","repository"].some((t=>this.props[t]!==e[t]))&&this.updateThings(e),e.imageId&&e.imageId.includes("${")&&this.setState({defineManually:!0})}componentWillUnmount(){this.unmounted=!0}synchronizeChanges(e,t){const{organization:a,repository:s,tag:i,digest:n}=e;if(this.props.onChange){const e=R.generateImageId({organization:a,repository:s,tag:i,digest:n}),o={};i!==this.props.tag&&(o.tag=i),e!==this.props.imageId&&(o.imageId=e),a!==this.props.organization&&(o.organization=a),t!==this.props.registry&&(o.registry=t),s!==this.props.repository&&(o.repository=s),n!==this.props.digest&&(o.digest=n),Object.keys(o).length>0&&this.props.onChange(o)}}updateThings(e,t=!1){if(!this.repositoryMap||this.unmounted)return;const{imageId:a,specifyTagByRegex:s}=e;let{organization:i,registry:n,repository:o}=e;e.showRegistry&&(n=this.registryMap[e.account]);const r=!i||this.organizations.includes(i)||i.includes("${");r||(i="");const l=this.getRepositoryList(this.organizationMap,i,n),c=!o||o.includes("${")||l.includes(o);c||(o="");const{tag:g,tags:m}=this.getTags(e.tag,this.repositoryMap,o),p=g===e.tag||s,d={accountOptions:this.newAccounts.sort().map((e=>({label:e,value:e}))),organizationOptions:this.organizations.filter((e=>e)).sort().map((e=>({label:e,value:e}))),imagesLoaded:!0,repositoryOptions:l.sort().map((e=>({label:e,value:e}))),tagOptions:m.sort().map((e=>({label:e,value:e})))};if(!a||this.state.imagesLoaded&&!t||r&&c&&p)a&&a.includes("${")||this.synchronizeChanges(this.state.defineManually?R.splitImageId(a):{organization:i,repository:o,tag:g,digest:this.props.digest},n);else{d.defineManually=!0;const e=[];r||e.push("organization"),c||e.push("image"),p||e.push("tag"),d.missingFields=e,d.switchedManualWarning=`Could not find ${e.join(" or ")}, switched to manual entry`}this.setState(d)}initializeImages(e){if(this.state.imagesLoading)return;const{showRegistry:t,account:a,registry:s}=e,i={provider:"dockerRegistry",account:t?a:s};this.setState({imagesLoading:!0}),L.findImages(i).then((t=>{this.images=t,this.registryMap=this.getRegistryMap(this.images),this.accountMap=this.getAccountMap(this.images),this.newAccounts=this.accounts||Object.keys(this.accountMap),this.organizationMap=this.getOrganizationMap(this.images),this.repositoryMap=this.getRepositoryMap(this.images),this.organizations=this.getOrganizationsList(this.accountMap),this.updateThings(e,!0)})).finally((()=>{this.unmounted||this.setState({imagesLoading:!1})}))}refreshImages(e){this.initializeImages(e)}initializeAccounts(e){let{account:t}=e;a.listAccounts("dockerRegistry").then((a=>{const s=a.map((e=>e.name));this.props.showRegistry&&!t&&(t=s[0]),this.accounts=s,this.refreshImages({...e,account:t})}))}isNew(){const{account:e,organization:t,registry:a,repository:s,tag:i}=this.props;return!(e||t||a||s||i)}componentDidMount(){this.props.deferInitialization||!this.props.registry&&!this.isNew()||this.initializeAccounts(this.props)}valueChanged(e,t){const a={[e]:t};if(x.some((t=>t===e))){const{organization:e,repository:t,tag:s,digest:i}=this.props,n={organization:e,repository:t,tag:s,digest:i,...a},o=R.generateImageId(n);a.imageId=o}this.props.onChange&&this.props.onChange(a)}render(){const{account:e,allowManualDefinition:t,digest:a,imageId:o,organization:r,repository:l,showDigest:c,showRegistry:g,specifyTagByRegex:m,tag:p}=this.props,{accountOptions:d,switchedManualWarning:u,missingFields:h,imagesLoading:f,lookupType:v,organizationOptions:y,repositoryOptions:N,defineManually:I,tagOptions:k}=this.state,C=R.splitImageId(o),z=E.createElement("div",{className:"sp-formItem groupHeader"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Define Image ID"),E.createElement("div",{className:"sp-formActions sp-formActions--mobile"},E.createElement("span",{className:"action"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{value:I,disabled:f||!t,onChange:e=>this.showManualInput(e.value),options:T,clearable:!1}))))),_=u?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"}),E.createElement("div",{className:"sp-formItem__right"},E.createElement(s,{type:"warning",message:E.createElement(E.Fragment,null,u,(h||[]).map((e=>E.createElement("div",{key:e},E.createElement(i,{expand:!0,id:`pipeline.config.docker.trigger.missing.${e}`})))))}))):null;if(I)return E.createElement("div",{className:"sp-formGroup"},z,E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Image ID"),E.createElement("div",{className:"sp-formActions sp-formActions--mobile"},E.createElement("span",{className:"action"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{className:"form-control input-sm",value:o||"",onChange:e=>this.valueChanged("imageId",e.target.value)}))))),_);const w=g?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Registry Name")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{value:e,disabled:f,onChange:e=>this.valueChanged("account",e?e.value:""),options:d,isLoading:f})),E.createElement("span",{className:"sp-formActions sp-formActions--web"},E.createElement("span",{className:"action"},E.createElement(n,{value:f?"Images refreshing":"Refresh images list"},E.createElement("i",{className:"fa icon-button-refresh-arrows "+(f?"fa-spin":""),onClick:this.handleRefreshImages}))))))):null,L=E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Organization")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},r.includes("${")?E.createElement("input",{disabled:f,className:"form-control input-sm",value:r||"",onChange:e=>this.valueChanged("organization",e.target.value)}):E.createElement(b,{value:r||"",disabled:f,onChange:e=>this.valueChanged("organization",e&&e.value||""),placeholder:"No organization",options:y,isLoading:f}))))),M=E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Image")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},l.includes("${")?E.createElement("input",{className:"form-control input-sm",disabled:f,value:l||"",onChange:e=>this.valueChanged("repository",e.target.value)}):E.createElement(b,{value:l||"",disabled:f,onChange:e=>this.valueChanged("repository",e&&e.value||""),options:N,required:!0,isLoading:f}))))),x="tag"===v?m?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Tag")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{type:"text",className:"form-control input-sm",value:p||"",disabled:f||!l,onChange:e=>this.valueChanged("tag",e.target.value)}))),E.createElement(i,{id:"pipeline.config.docker.trigger.tag",expand:!0}))):E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Tag")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},p&&p.includes("${")?E.createElement("input",{className:"form-control input-sm",disabled:f,value:p||"",onChange:e=>this.valueChanged("tag",e.target.value),required:!0}):E.createElement(E.Fragment,null,E.createElement(b,{value:p||"",disabled:f||!l,isLoading:f,onChange:e=>this.valueChanged("tag",e?e.value:void 0),options:k,placeholder:"No tag",required:!0}),E.createElement(i,{id:"pipeline.config.docker.trigger.tag.additionalInfo",expand:!0})))))):null,S="digest"===v?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Digest ",E.createElement(i,{id:"pipeline.config.docker.trigger.digest"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{className:"form-control input-sm",placeholder:"sha256:abc123",value:a||C.digest||"",onChange:e=>this.valueChanged("digest",e.target.value),required:!0}))))):null,O=c?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Type")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{clearable:!1,value:v,options:[{value:"digest",label:"Digest"},{value:"tag",label:"Tag"}],onChange:this.lookupTypeChanged}))))):null;return E.createElement("div",{className:"sp-formGroup"},z,w,L,M,O,S,x)}}S.defaultProps={organization:"",registry:"",repository:"",showDigest:!0,allowManualDefinition:!0};const O="spinnaker.docker.pipeline.stage.bake.executionDetails.controller";N(O,[I]).controller("dockerBakeExecutionDetailsCtrl",["$scope","$stateParams","executionDetailsSectionService","$interpolate",function(e,t,a,s){e.configSections=["bakeConfig","taskStatus"];const i=()=>{e.detailsSection=t.details,e.provider=e.stage.context.cloudProviderType||"docker",e.bakeryDetailUrl=s(e.roscoMode&&o.roscoDetailUrl?o.roscoDetailUrl:o.bakeryDetailUrl)},n=()=>a.synchronizeSection(e.configSections,i);n(),e.$on("$stateChangeSuccess",n)}]);const D="spinnaker.docker.pipeline.stage.bakeStage";N(D,[O]).config((function(){r.pipeline.registerStage({provides:"bake",cloudProvider:"docker",label:"Bake",description:"Bakes an image",templateUrl:"docker/src/pipeline/stages/bake/bakeStage.html",executionDetailsUrl:"docker/src/pipeline/stages/bake/bakeExecutionDetails.html",executionLabelComponent:l,extraLabelLines:e=>e.masterStage.context.allPreviouslyBaked||e.masterStage.context.somePreviouslyBaked?1:0,supportsCustomTimeout:!0,validators:[{type:"requiredField",fieldName:"package"}],restartable:!0})})).controller("dockerBakeStageCtrl",["$scope","$q",function(e,t){e.stage.region="global",e.stage.user||(e.stage.user=c.getAuthenticatedUser().name),e.viewState={loading:!0},e.$watch("stage",(function(){d.forOwn(e.stage,(function(t,a){""===t&&delete e.stage[a]}))}),!0),e.viewState.providerSelected=!0,t.all([g.getBaseOsOptions("docker"),g.getBaseLabelOptions()]).then((function([t,a]){e.baseOsOptions=t.baseImages,e.baseLabelOptions=a,!e.stage.baseOs&&e.baseOsOptions&&e.baseOsOptions.length&&(e.stage.baseOs=e.baseOsOptions[0].id),!e.stage.baseLabel&&e.baseLabelOptions&&e.baseLabelOptions.length&&(e.stage.baseLabel=e.baseLabelOptions[0]),e.viewState.loading=!1}))}]),window.angular.module("ng").run(["$templateCache",function(e){e.put("docker/src/pipeline/stages/bake/bakeStage.html",'<div ng-controller="dockerBakeStageCtrl as bakeStageCtrl">\n <stage-config-field label="Package" help-key="pipeline.config.bake.package">\n <input type="text" class="form-control input-sm" ng-model="stage.package" />\n </stage-config-field>\n <stage-config-field label="Organization" help-key="pipeline.config.docker.bake.organization">\n <input type="text" class="form-control input-sm" ng-model="stage.organization" />\n </stage-config-field>\n <stage-config-field label="Image Name" help-key="pipeline.config.docker.bake.targetImage">\n <input type="text" class="form-control input-sm" ng-model="stage.ami_name" />\n </stage-config-field>\n <stage-config-field label="Image tag" help-key="pipeline.config.docker.bake.targetImageTag">\n <input type="text" class="form-control input-sm" ng-model="stage.extendedAttributes[\'docker_target_image_tag\']" />\n </stage-config-field>\n <stage-config-field label="Base OS">\n <bake-stage-choose-os model="stage.baseOs" base-os-options="baseOsOptions"></bake-stage-choose-os>\n </stage-config-field>\n\n <stage-config-field label="Base Label">\n <label class="radio-inline" ng-repeat="baseLabel in baseLabelOptions">\n <input type="radio" ng-model="stage.baseLabel" ng-value="baseLabel" />\n {{baseLabel}}\n </label>\n </stage-config-field>\n <stage-config-field label="Rebake">\n <div class="checkbox" style="margin-bottom: 0">\n <label>\n <input type="checkbox" ng-model="stage.rebake" />\n Rebake image without regard to the status of any existing bake\n </label>\n </div>\n </stage-config-field>\n</div>\n')}]),window.angular.module("ng").run(["$templateCache",function(e){e.put("docker/src/pipeline/stages/bake/bakeExecutionDetails.html",'<div ng-controller="dockerBakeExecutionDetailsCtrl">\n <execution-details-section-nav sections="configSections"></execution-details-section-nav>\n <div class="step-section-details" ng-if="detailsSection === \'bakeConfig\'">\n <div class="row">\n <div class="col-md-6">\n <dl class="dl-narrow dl-horizontal">\n <dt if-multiple-providers>Provider</dt>\n <dd if-multiple-providers>Docker</dd>\n <dt>Organization</dt>\n <dd>{{stage.context.organization}}</dd>\n <dt>Image Name</dt>\n <dd>{{stage.context.ami_name}}</dd>\n <dt>Image Tag</dt>\n <dd>{{stage.context.extendedAttributes[\'docker_target_image_tag\']}}</dd>\n <dt>Image</dt>\n <dd>{{stage.context.ami}}</dd>\n </dl>\n </div>\n <div class="col-md-6">\n <dl class="dl-narrow dl-horizontal">\n <dt>Base OS</dt>\n <dd>{{stage.context.baseOs}}</dd>\n <dt>Region</dt>\n <dd>{{stage.context.region}}</dd>\n <dt>Package</dt>\n <dd>{{stage.context.package}}</dd>\n <dt>Label</dt>\n <dd>{{stage.context.baseLabel}}</dd>\n </dl>\n </div>\n </div>\n <stage-failure-message stage="stage" message="stage.failureMessage"></stage-failure-message>\n\n <div class="row" ng-if="stage.context.region && stage.context.status.resourceId">\n <div class="col-md-12">\n <div class="alert alert-{{stage.isFailed ? \'danger\' : \'info\'}}">\n <a target="_blank" href="{{ bakeryDetailUrl(stage) }}"> View Bakery Details </a>\n </div>\n </div>\n </div>\n </div>\n <div class="step-section-details" ng-if="detailsSection === \'taskStatus\'">\n <div class="row">\n <execution-step-details item="stage"></execution-step-details>\n </div>\n </div>\n</div>\n')}]);const $=["organization","repository","tag","digest"],A=[{label:"Manually",value:!0},{label:"Select from list",value:!1}];class q extends E.Component{constructor(e){super(e),this.unmounted=!1,this.cachedValues={},this.handleRefreshImages=()=>{this.refreshImages(this.props)},this.lookupTypeChanged=e=>{const t=e.value,a=this.state.lookupType,s=this.props[a],i=this.cachedValues[t];this.valueChanged(a,void 0),this.cachedValues[t]&&this.valueChanged(t,i),this.setState({lookupType:t}),this.cachedValues[a]=s},this.showManualInput=e=>{if(!e){const e=R.splitImageId(this.props.imageId||"");this.props.onChange(e),this.state.switchedManualWarning&&this.setState({switchedManualWarning:void 0,missingFields:void 0})}this.setState({defineManually:e})};const t=e.account?[{label:e.account,value:e.account}]:[],a=e.organization&&e.organization.length?[{label:e.organization,value:e.organization}]:[],s=e.repository&&e.repository.length?[{label:e.repository,value:e.repository}]:[],i=e.tag&&e.tag.length?[{label:e.tag,value:e.tag}]:[],n=R.splitImageId(e.imageId),o=e.allowManualDefinition&&Boolean(e.imageId&&e.imageId.includes("${"));this.state={accountOptions:t,switchedManualWarning:void 0,imagesLoaded:!1,imagesLoading:!1,organizationOptions:a,repositoryOptions:s,defineManually:o,tagOptions:i,lookupType:e.digest||n.digest?"digest":"tag"}}getAccountMap(e){const t=u(e.filter((e=>e.account)),"account");return h(t,((e,t,a)=>(e[a]=f(t.map((e=>`${e.repository.split("/").slice(0,-1).join("/")}`))),e)),{})}getRegistryMap(e){return e.reduce(((e,t)=>(e[t.account]=t.registry,e)),{})}getOrganizationMap(e){const t=u(e.filter((e=>e.repository)),(e=>`${e.account}/${e.repository.split("/").slice(0,-1).join("/")}`));return h(t,((e,t,a)=>(e[a]=f(t.map((e=>e.repository))),e)),{})}getRepositoryMap(e){const t=u(e.filter((e=>e.account)),"repository");return h(t,((e,t,a)=>(e[a]=f(t.map((e=>e.tag))),e)),{})}getOrganizationsList(e){return e&&e[this.props.showRegistry?this.props.account:this.props.registry]||[]}getRepositoryList(e,t,a){if(e){return e[`${this.props.showRegistry?this.props.account:a}/${t||""}`]||[]}return[]}getTags(e,t,a){let s=[];return this.props.specifyTagByRegex?e&&""===v(e)&&(e=void 0):t&&(s=t[a]||[],s.includes(e)||!e||e.includes("${")||(e=void 0)),{tag:e,tags:s}}componentWillReceiveProps(e){!this.images||["account","showRegistry"].some((t=>this.props[t]!==e[t]))?this.refreshImages(e):["organization","registry","repository"].some((t=>this.props[t]!==e[t]))&&this.updateThings(e),e.imageId&&e.imageId.includes("${")&&this.setState({defineManually:!0})}componentWillUnmount(){this.unmounted=!0}synchronizeChanges(e,t){const{organization:a,repository:s,tag:i,digest:n}=e;if(this.props.onChange){const e=R.generateImageId({organization:a,repository:s,tag:i,digest:n}),o={};i!==this.props.tag&&(o.tag=i),e!==this.props.imageId&&(o.imageId=e),a!==this.props.organization&&(o.organization=a),t!==this.props.registry&&(o.registry=t),s!==this.props.repository&&(o.repository=s),n!==this.props.digest&&(o.digest=n),Object.keys(o).length>0&&this.props.onChange(o)}}updateThings(e,t=!1){if(!this.repositoryMap||this.unmounted)return;const{imageId:a,specifyTagByRegex:s}=e;let{organization:i,registry:n,repository:o}=e;e.showRegistry&&(n=this.registryMap[e.account]);const r=!i||this.organizations.includes(i)||i.includes("${");r||(i="");const l=this.getRepositoryList(this.organizationMap,i,n),c=!o||o.includes("${")||l.includes(o);c||(o="");const{tag:g,tags:m}=this.getTags(e.tag,this.repositoryMap,o),p=g===e.tag||s,d={accountOptions:this.newAccounts.sort().map((e=>({label:e,value:e}))),organizationOptions:this.organizations.filter((e=>e)).sort().map((e=>({label:e,value:e}))),imagesLoaded:!0,repositoryOptions:l.sort().map((e=>({label:e,value:e}))),tagOptions:m.sort().map((e=>({label:e,value:e})))};if(!a||this.state.imagesLoaded&&!t||r&&c&&p)a&&a.includes("${")||this.synchronizeChanges(this.state.defineManually?R.splitImageId(a):{organization:i,repository:o,tag:g,digest:this.props.digest},n);else{d.defineManually=!0;const e=[];r||e.push("organization"),c||e.push("image"),p||e.push("tag"),d.missingFields=e,d.switchedManualWarning=`Could not find ${e.join(" or ")}, switched to manual entry`}this.setState(d)}initializeImages(e){if(this.state.imagesLoading)return;const{showRegistry:t,account:a,registry:s}=e,i={provider:"dockerRegistry",account:t?a:s};this.setState({imagesLoading:!0}),M.findImages(i).then((t=>{this.images=t,this.registryMap=this.getRegistryMap(this.images),this.accountMap=this.getAccountMap(this.images),this.newAccounts=this.accounts||Object.keys(this.accountMap),this.organizationMap=this.getOrganizationMap(this.images),this.repositoryMap=this.getRepositoryMap(this.images),this.organizations=this.getOrganizationsList(this.accountMap),this.updateThings(e,!0)})).finally((()=>{this.unmounted||this.setState({imagesLoading:!1})}))}refreshImages(e){this.initializeImages(e)}initializeAccounts(e){let{account:t}=e;a.listAccounts("dockerRegistry").then((a=>{const s=a.map((e=>e.name));this.props.showRegistry&&!t&&(t=s[0]),this.accounts=s,this.refreshImages({...e,account:t})}))}isNew(){const{account:e,organization:t,registry:a,repository:s,tag:i}=this.props;return!(e||t||a||s||i)}componentDidMount(){this.props.deferInitialization||!this.props.registry&&!this.isNew()||this.initializeAccounts(this.props)}valueChanged(e,t){const a={[e]:t};if($.some((t=>t===e))){const{organization:e,repository:t,tag:s,digest:i}=this.props,n={organization:e,repository:t,tag:s,digest:i,...a},o=R.generateImageId(n);a.imageId=o}this.props.onChange&&this.props.onChange(a)}render(){const{account:e,allowManualDefinition:t,digest:a,imageId:o,organization:r,repository:l,showDigest:c,showRegistry:g,specifyTagByRegex:m,tag:p}=this.props,{accountOptions:d,switchedManualWarning:u,missingFields:h,imagesLoading:f,lookupType:v,organizationOptions:y,repositoryOptions:N,defineManually:I,tagOptions:k}=this.state,C=R.splitImageId(o),z=E.createElement("div",{className:"sp-formItem groupHeader"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Define Image ID"),E.createElement("div",{className:"sp-formActions sp-formActions--mobile"},E.createElement("span",{className:"action"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{value:I,disabled:f||!t,onChange:e=>this.showManualInput(e.value),options:A,clearable:!1}))))),_=u?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"}),E.createElement("div",{className:"sp-formItem__right"},E.createElement(s,{type:"warning",message:E.createElement(E.Fragment,null,u,(h||[]).map((e=>E.createElement("div",{key:e},E.createElement(i,{expand:!0,id:`pipeline.config.docker.trigger.missing.${e}`})))))}))):null;if(I)return E.createElement("div",{className:"sp-formGroup"},z,E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Image ID"),E.createElement("div",{className:"sp-formActions sp-formActions--mobile"},E.createElement("span",{className:"action"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{className:"form-control input-sm",value:o||"",onChange:e=>this.valueChanged("imageId",e.target.value)}))))),_);const w=g?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Registry Name")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{value:e,disabled:f,onChange:e=>this.valueChanged("account",e?e.value:""),options:d,isLoading:f})),E.createElement("span",{className:"sp-formActions sp-formActions--web"},E.createElement("span",{className:"action"},E.createElement(n,{value:f?"Images refreshing":"Refresh images list"},E.createElement("i",{className:"fa icon-button-refresh-arrows "+(f?"fa-spin":""),onClick:this.handleRefreshImages}))))))):null,L=E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Organization")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},r.includes("${")?E.createElement("input",{disabled:f,className:"form-control input-sm",value:r||"",onChange:e=>this.valueChanged("organization",e.target.value)}):E.createElement(b,{value:r||"",disabled:f,onChange:e=>this.valueChanged("organization",e&&e.value||""),placeholder:"No organization",options:y,isLoading:f}))))),M=E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Image")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},l.includes("${")?E.createElement("input",{className:"form-control input-sm",disabled:f,value:l||"",onChange:e=>this.valueChanged("repository",e.target.value)}):E.createElement(b,{value:l||"",disabled:f,onChange:e=>this.valueChanged("repository",e&&e.value||""),options:N,required:!0,isLoading:f}))))),x="tag"===v?m?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Tag")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{type:"text",className:"form-control input-sm",value:p||"",disabled:f||!l,onChange:e=>this.valueChanged("tag",e.target.value)}))),E.createElement(i,{id:"pipeline.config.docker.trigger.tag",expand:!0}))):E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Tag")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},p&&p.includes("${")?E.createElement("input",{className:"form-control input-sm",disabled:f,value:p||"",onChange:e=>this.valueChanged("tag",e.target.value),required:!0}):E.createElement(E.Fragment,null,E.createElement(b,{value:p||"",disabled:f||!l,isLoading:f,onChange:e=>this.valueChanged("tag",e?e.value:void 0),options:k,placeholder:"No tag",required:!0}),E.createElement(i,{id:"pipeline.config.docker.trigger.tag.additionalInfo",expand:!0})))))):null,T="digest"===v?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Digest ",E.createElement(i,{id:"pipeline.config.docker.trigger.digest"}))),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement("input",{className:"form-control input-sm",placeholder:"sha256:abc123",value:a||C.digest||"",onChange:e=>this.valueChanged("digest",e.target.value),required:!0}))))):null,S=c?E.createElement("div",{className:"sp-formItem"},E.createElement("div",{className:"sp-formItem__left"},E.createElement("div",{className:"sp-formLabel"},"Type")),E.createElement("div",{className:"sp-formItem__right"},E.createElement("div",{className:"sp-form"},E.createElement("span",{className:"field"},E.createElement(b,{clearable:!1,value:v,options:[{value:"digest",label:"Digest"},{value:"tag",label:"Tag"}],onChange:this.lookupTypeChanged}))))):null;return E.createElement("div",{className:"sp-formGroup"},z,w,L,M,S,T,x)}}q.defaultProps={organization:"",registry:"",repository:"",showDigest:!0,allowManualDefinition:!0};const F=[{value:"digest",label:"Digest"},{value:"tag",label:"Tag"}];class B extends E.Component{constructor(e){super(e),this.queryStream=new C,this.handleQuery=()=>{const e=this.props.command.trigger;return"helm/oci"===e.type?z(M.findTags({provider:"dockerRegistry",account:e.account,repository:e.repository})):z(L.findTags({provider:"dockerRegistry",account:e.account,repository:e.repository}))},this.lookupTypeChanged=e=>{const t=e.value;this.updateArtifact(this.props.command,"tag"===t?this.state.selectedTag:this.state.digest),this.setState({lookupType:t})},this.updateSelectedTag=e=>{this.updateArtifact(this.props.command,e),this.setState({selectedTag:e}),this.props.command.triggerInvalid=!1},this.updateDigest=e=>{this.updateArtifact(this.props.command,e),this.setState({digest:e})},this.tagLoadSuccess=e=>{const{command:t}=this.props,a=t.trigger,s={};s.tags=e||[];const i=s.tags.find((e=>e===a.tag));i&&(s.selectedTag=i,this.updateSelectedTag(i)),s.tagsLoading=!1,this.setState(s)},this.tagLoadFailure=()=>{this.setState({tagsLoading:!1,loadError:!0})},this.initialize=()=>{const{command:e}=this.props;this.props.updateCommand("triggerInvalid",!0),this.props.updateCommand("extraFields",{tag:y(e,"extraFields.tag",""),artifacts:y(e,"extraFields.artifacts","")}),this.subscription&&this.subscription.unsubscribe(),"docker"!==e.trigger.type&&"helm/oci"!==e.trigger.type||(this.subscription=this.queryStream.pipe(_(250),w(this.handleQuery)).subscribe(this.tagLoadSuccess,this.tagLoadFailure),this.searchTags())},this.searchTags=(e="")=>{this.setState({tags:[`<span>Finding tags${e&&` matching ${e}`}...</span>`]}),this.queryStream.next()},this.state={digest:"",tags:[],tagsLoading:!0,loadError:!1,lookupType:"tag",selectedTag:""}}static formatLabel(e){return k.when(`(Docker Registry) ${e.account?e.account+":":""} ${e.repository||""}`)}updateArtifact(e,t){this.props.updateCommand("extraFields.tag",t);const a=e.trigger;if(a&&a.repository){let e="";a.registry&&(e+=a.registry+"/"),e+=a.repository;let s="";s="digest"===this.state.lookupType?`${e}@${t}`:`${e}:${t}`;const i="docker"===a.type?"docker/image":"helm/image";this.props.updateCommand("extraFields.artifacts",[{type:i,name:e,version:t,reference:s}])}}componentDidMount(){this.initialize()}componentWillUnmount(){this.subscription&&this.subscription.unsubscribe()}render(){const{digest:e,tags:t,tagsLoading:a,loadError:s,selectedTag:n,lookupType:o}=this.state,r=t.map((e=>({value:e})));return E.createElement(E.Fragment,null,E.createElement("div",{className:"form-group"},E.createElement("div",{className:"sm-label-right col-md-4"},"Type"),E.createElement("div",{className:"col-md-3"},E.createElement(m,{clearable:!1,value:o,options:F,onChange:this.lookupTypeChanged}))),"tag"===o&&E.createElement("div",{className:"form-group"},E.createElement("label",{className:"col-md-4 sm-label-right"},"Tag"),a&&E.createElement("div",{className:"col-md-6"},E.createElement("div",{className:"form-control-static text-center"},E.createElement(p,{size:"small"}))),s&&E.createElement("div",{className:"col-md-6"},"Error loading tags!"),!a&&E.createElement("div",{className:"col-md-6"},0===t.length&&E.createElement("div",null,E.createElement("p",{className:"form-control-static"},"No tags found")),t.length>0&&E.createElement(m,{options:r,optionRenderer:e=>E.createElement("span",null,e.value),clearable:!1,value:n,valueRenderer:e=>E.createElement("span",null,E.createElement("strong",null,e.value)),onChange:e=>this.updateSelectedTag(e.value),placeholder:"Search tags..."}))),"digest"===o&&E.createElement("div",{className:"form-group"},E.createElement("label",{className:"col-md-4 sm-label-right"},"Digest ",E.createElement(i,{id:"pipeline.config.docker.trigger.digest"})),E.createElement("div",{className:"col-md-6"},E.createElement("input",{value:e,onChange:e=>this.updateDigest(e.target.value),className:"form-control input-sm",required:!0}))))}}const W=e=>{const t=e.trigger;return E.createElement("li",null,t.repository,":",t.tag)};r.pipeline.registerTrigger({label:"Docker Registry",description:"Executes the pipeline on an image update",key:"docker",component:function(e){const{formik:t}=e,a=t.values;return E.createElement("div",{className:"form-horizontal"},E.createElement(S,{allowManualDefinition:!1,specifyTagByRegex:!0,account:a.account,organization:a.organization,registry:a.registry,repository:a.repository,tag:a.tag,showRegistry:!0,onChange:t=>{const{imageId:a,...s}=t;e.triggerUpdated(s)},showDigest:!1}))},manualExecutionComponent:B,executionStatusComponent:W,executionTriggerLabel:()=>"Docker Registry",validators:[{type:"requiredField",fieldName:"account",message:"<strong>Registry</strong> is a required field for Docker Registry triggers."},{type:"requiredField",fieldName:"repository",message:"<strong>Image</strong> is a required field for Docker Registry triggers."},{type:"serviceAccountAccess",preventSave:!0,message:"You do not have access to the service account configured in this pipeline's Docker Registry trigger.\n You will not be able to save your edits to this pipeline."}]}),r.pipeline.registerTrigger({label:"Helm Docker Registry",description:"Executes the pipeline on an helm/image update",key:"helm/oci",component:function(e){const{formik:t}=e,a=t.values;return E.createElement("div",{className:"form-horizontal"},E.createElement(q,{allowManualDefinition:!1,specifyTagByRegex:!0,account:a.account,organization:a.organization,registry:a.registry,repository:a.repository,tag:a.tag,showRegistry:!0,onChange:t=>{const{imageId:a,...s}=t;e.triggerUpdated(s)},showDigest:!1}))},manualExecutionComponent:B,executionStatusComponent:W,executionTriggerLabel:()=>"Helm Docker Registry",validators:[{type:"requiredField",fieldName:"account",message:"<strong>Registry</strong> is a required field for Docker Registry triggers."},{type:"requiredField",fieldName:"repository",message:"<strong>Image</strong> is a required field for Docker Registry triggers."},{type:"serviceAccountAccess",preventSave:!0,message:"You do not have access to the service account configured in this pipeline's Docker Registry trigger.\n You will not be able to save your edits to this pipeline."}]});const j="spinnaker.docker";N(j,[D]);export{j as DOCKER_MODULE,M as DockerChartImageReader,S as DockerImageAndTagSelector,L as DockerImageReader,R as DockerImageUtils};
1
+ import { REST, RetryService, AccountService, ValidationMessage, HelpField, Tooltip, SETTINGS, Registry, BakeExecutionLabel, AuthenticationService, BakeryReader, TetheredSelect, Spinner } from '@spinnaker/core';
2
+ import _, { groupBy, reduce, uniq, trim, get } from 'lodash';
3
+ import React from 'react';
4
+ import Select from 'react-select';
5
+ import { module } from 'angular';
6
+ import UIROUTER_ANGULARJS from '@uirouter/angularjs';
7
+ import { $q } from 'ngimport';
8
+ import { Subject, from } from 'rxjs';
9
+ import { debounceTime, switchMap } from 'rxjs/operators';
10
+
11
+ class DockerImageReader {
12
+ static getImage(imageName, region, credentials) {
13
+ return REST("/images").path(credentials, region, imageName).query({ provider: "docker" }).get().then((results) => results && results.length ? results[0] : null).catch(() => null);
14
+ }
15
+ static findImages(params) {
16
+ return RetryService.buildRetrySequence(() => REST("/images/find").query(params).get(), (results) => results.length > 0, 10, 1e3).then((results) => results).catch(() => []);
17
+ }
18
+ static findTags(params) {
19
+ return RetryService.buildRetrySequence(() => REST("/images/tags").query(params).get(), (results) => results.length > 0, 10, 1e3).then((results) => results).catch(() => []);
20
+ }
21
+ }
22
+ class DockerChartImageReader {
23
+ static getImage(imageName, region, credentials) {
24
+ return REST("/charts").path(credentials, region, imageName).query({ provider: "docker" }).get().then((results) => results && results.length ? results[0] : null).catch(() => null);
25
+ }
26
+ static findImages(params) {
27
+ return RetryService.buildRetrySequence(() => REST("/charts/find").query(params).get(), (results) => results.length > 0, 10, 1e3).then((results) => results).catch(() => []);
28
+ }
29
+ static findTags(params) {
30
+ return RetryService.buildRetrySequence(() => REST("/charts/tags").query(params).get(), (results) => results.length > 0, 10, 1e3).then((results) => results).catch(() => []);
31
+ }
32
+ }
33
+
34
+ class DockerImageUtils {
35
+ static splitImageId(imageId = "") {
36
+ let imageParts;
37
+ if (imageId.includes("@")) {
38
+ imageParts = imageId.split("@");
39
+ } else {
40
+ imageParts = imageId.split(":");
41
+ }
42
+ const repository = imageParts[0];
43
+ const repositoryParts = repository.split("/");
44
+ const organization = repositoryParts.slice(0, -1).join("/");
45
+ const lookup = imageParts.length > 1 ? imageParts.slice(1).join(":") : "";
46
+ let tag;
47
+ let digest;
48
+ if (lookup) {
49
+ if (lookup.startsWith("sha256:")) {
50
+ digest = lookup;
51
+ } else {
52
+ tag = lookup;
53
+ }
54
+ }
55
+ return { organization, repository, digest, tag };
56
+ }
57
+ static generateImageId(parts) {
58
+ if (!parts.repository || !(parts.digest || parts.tag)) {
59
+ return void 0;
60
+ }
61
+ let imageId;
62
+ if (parts.digest) {
63
+ imageId = `${parts.repository}@${parts.digest}`;
64
+ } else {
65
+ imageId = `${parts.repository}:${parts.tag}`;
66
+ }
67
+ return imageId;
68
+ }
69
+ }
70
+
71
+ const imageFields$1 = ["organization", "repository", "tag", "digest"];
72
+ const defineOptions$1 = [
73
+ { label: "Manually", value: true },
74
+ { label: "Select from list", value: false }
75
+ ];
76
+ class DockerImageAndTagSelector extends React.Component {
77
+ constructor(props) {
78
+ super(props);
79
+ this.unmounted = false;
80
+ this.cachedValues = {};
81
+ this.handleRefreshImages = () => {
82
+ this.refreshImages(this.props);
83
+ };
84
+ this.lookupTypeChanged = (o) => {
85
+ const newType = o.value;
86
+ const oldType = this.state.lookupType;
87
+ const oldValue = this.props[oldType];
88
+ const cachedValue = this.cachedValues[newType];
89
+ this.valueChanged(oldType, void 0);
90
+ if (this.cachedValues[newType]) {
91
+ this.valueChanged(newType, cachedValue);
92
+ }
93
+ this.setState({ lookupType: newType });
94
+ this.cachedValues[oldType] = oldValue;
95
+ };
96
+ this.showManualInput = (defineManually) => {
97
+ if (!defineManually) {
98
+ const newFields = DockerImageUtils.splitImageId(this.props.imageId || "");
99
+ this.props.onChange(newFields);
100
+ if (this.state.switchedManualWarning) {
101
+ this.setState({ switchedManualWarning: void 0, missingFields: void 0 });
102
+ }
103
+ }
104
+ this.setState({ defineManually });
105
+ };
106
+ const accountOptions = props.account ? [{ label: props.account, value: props.account }] : [];
107
+ const organizationOptions = props.organization && props.organization.length ? [{ label: props.organization, value: props.organization }] : [];
108
+ const repositoryOptions = props.repository && props.repository.length ? [{ label: props.repository, value: props.repository }] : [];
109
+ const tagOptions = props.tag && props.tag.length ? [{ label: props.tag, value: props.tag }] : [];
110
+ const parsedImageId = DockerImageUtils.splitImageId(props.imageId);
111
+ const defineManually = props.allowManualDefinition && Boolean(props.imageId && props.imageId.includes("${"));
112
+ this.state = {
113
+ accountOptions,
114
+ switchedManualWarning: void 0,
115
+ imagesLoaded: false,
116
+ imagesLoading: false,
117
+ organizationOptions,
118
+ repositoryOptions,
119
+ defineManually,
120
+ tagOptions,
121
+ lookupType: props.digest || parsedImageId.digest ? "digest" : "tag"
122
+ };
123
+ }
124
+ getAccountMap(images) {
125
+ const groupedImages = groupBy(images.filter((image) => image.account), "account");
126
+ return reduce(groupedImages, (acc, image, key) => {
127
+ acc[key] = uniq(image.map((i) => `${i.repository.split("/").slice(0, -1).join("/")}`));
128
+ return acc;
129
+ }, {});
130
+ }
131
+ getRegistryMap(images) {
132
+ return images.reduce((m, image) => {
133
+ m[image.account] = image.registry;
134
+ return m;
135
+ }, {});
136
+ }
137
+ getOrganizationMap(images) {
138
+ const extractGroupByKey = (image) => `${image.account}/${image.repository.split("/").slice(0, -1).join("/")}`;
139
+ const groupedImages = groupBy(images.filter((image) => image.repository), extractGroupByKey);
140
+ return reduce(groupedImages, (acc, image, key) => {
141
+ acc[key] = uniq(image.map((i) => i.repository));
142
+ return acc;
143
+ }, {});
144
+ }
145
+ getRepositoryMap(images) {
146
+ const groupedImages = groupBy(images.filter((image) => image.account), "repository");
147
+ return reduce(groupedImages, (acc, image, key) => {
148
+ acc[key] = uniq(image.map((i) => i.tag));
149
+ return acc;
150
+ }, {});
151
+ }
152
+ getOrganizationsList(accountMap) {
153
+ return accountMap ? accountMap[this.props.showRegistry ? this.props.account : this.props.registry] || [] : [];
154
+ }
155
+ getRepositoryList(organizationMap, organization, registry) {
156
+ if (organizationMap) {
157
+ const key = `${this.props.showRegistry ? this.props.account : registry}/${organization || ""}`;
158
+ return organizationMap[key] || [];
159
+ }
160
+ return [];
161
+ }
162
+ getTags(tag, repositoryMap, repository) {
163
+ let tags = [];
164
+ if (this.props.specifyTagByRegex) {
165
+ if (tag && trim(tag) === "") {
166
+ tag = void 0;
167
+ }
168
+ } else {
169
+ if (repositoryMap) {
170
+ tags = repositoryMap[repository] || [];
171
+ if (!tags.includes(tag) && tag && !tag.includes("${")) {
172
+ tag = void 0;
173
+ }
174
+ }
175
+ }
176
+ return { tag, tags };
177
+ }
178
+ componentWillReceiveProps(nextProps) {
179
+ if (!this.images || ["account", "showRegistry"].some((key) => this.props[key] !== nextProps[key])) {
180
+ this.refreshImages(nextProps);
181
+ } else if (["organization", "registry", "repository"].some((key) => this.props[key] !== nextProps[key])) {
182
+ this.updateThings(nextProps);
183
+ }
184
+ if (nextProps.imageId && nextProps.imageId.includes("${")) {
185
+ this.setState({ defineManually: true });
186
+ }
187
+ }
188
+ componentWillUnmount() {
189
+ this.unmounted = true;
190
+ }
191
+ synchronizeChanges(values, registry) {
192
+ const { organization, repository, tag, digest } = values;
193
+ if (this.props.onChange) {
194
+ const imageId = DockerImageUtils.generateImageId({ organization, repository, tag, digest });
195
+ const changes = {};
196
+ if (tag !== this.props.tag) {
197
+ changes.tag = tag;
198
+ }
199
+ if (imageId !== this.props.imageId) {
200
+ changes.imageId = imageId;
201
+ }
202
+ if (organization !== this.props.organization) {
203
+ changes.organization = organization;
204
+ }
205
+ if (registry !== this.props.registry) {
206
+ changes.registry = registry;
207
+ }
208
+ if (repository !== this.props.repository) {
209
+ changes.repository = repository;
210
+ }
211
+ if (digest !== this.props.digest) {
212
+ changes.digest = digest;
213
+ }
214
+ if (Object.keys(changes).length > 0) {
215
+ this.props.onChange(changes);
216
+ }
217
+ }
218
+ }
219
+ updateThings(props, allowAutoSwitchToManualEntry = false) {
220
+ if (!this.repositoryMap || this.unmounted) {
221
+ return;
222
+ }
223
+ const { imageId, specifyTagByRegex } = props;
224
+ let { organization, registry, repository } = props;
225
+ if (props.showRegistry) {
226
+ registry = this.registryMap[props.account];
227
+ }
228
+ const organizationFound = !organization || this.organizations.includes(organization) || organization.includes("${");
229
+ if (!organizationFound) {
230
+ organization = "";
231
+ }
232
+ const repositories = this.getRepositoryList(this.organizationMap, organization, registry);
233
+ const repositoryFound = !repository || repository.includes("${") || repositories.includes(repository);
234
+ if (!repositoryFound) {
235
+ repository = "";
236
+ }
237
+ const { tag, tags } = this.getTags(props.tag, this.repositoryMap, repository);
238
+ const tagFound = tag === props.tag || specifyTagByRegex;
239
+ const newState = {
240
+ accountOptions: this.newAccounts.sort().map((a) => ({ label: a, value: a })),
241
+ organizationOptions: this.organizations.filter((o) => o).sort().map((o) => ({ label: o, value: o })),
242
+ imagesLoaded: true,
243
+ repositoryOptions: repositories.sort().map((r) => ({ label: r, value: r })),
244
+ tagOptions: tags.sort().map((t) => ({ label: t, value: t }))
245
+ };
246
+ if (imageId && (!this.state.imagesLoaded || allowAutoSwitchToManualEntry) && (!organizationFound || !repositoryFound || !tagFound)) {
247
+ newState.defineManually = true;
248
+ const missingFields = [];
249
+ if (!organizationFound) {
250
+ missingFields.push("organization");
251
+ }
252
+ if (!repositoryFound) {
253
+ missingFields.push("image");
254
+ }
255
+ if (!tagFound) {
256
+ missingFields.push("tag");
257
+ }
258
+ newState.missingFields = missingFields;
259
+ newState.switchedManualWarning = `Could not find ${missingFields.join(" or ")}, switched to manual entry`;
260
+ } else if (!imageId || !imageId.includes("${")) {
261
+ this.synchronizeChanges(this.state.defineManually ? DockerImageUtils.splitImageId(imageId) : { organization, repository, tag, digest: this.props.digest }, registry);
262
+ }
263
+ this.setState(newState);
264
+ }
265
+ initializeImages(props) {
266
+ if (this.state.imagesLoading) {
267
+ return;
268
+ }
269
+ const { showRegistry, account, registry } = props;
270
+ const imageConfig = {
271
+ provider: "dockerRegistry",
272
+ account: showRegistry ? account : registry
273
+ };
274
+ this.setState({ imagesLoading: true });
275
+ DockerImageReader.findImages(imageConfig).then((images) => {
276
+ this.images = images;
277
+ this.registryMap = this.getRegistryMap(this.images);
278
+ this.accountMap = this.getAccountMap(this.images);
279
+ this.newAccounts = this.accounts || Object.keys(this.accountMap);
280
+ this.organizationMap = this.getOrganizationMap(this.images);
281
+ this.repositoryMap = this.getRepositoryMap(this.images);
282
+ this.organizations = this.getOrganizationsList(this.accountMap);
283
+ this.updateThings(props, true);
284
+ }).finally(() => {
285
+ if (!this.unmounted) {
286
+ this.setState({ imagesLoading: false });
287
+ }
288
+ });
289
+ }
290
+ refreshImages(props) {
291
+ this.initializeImages(props);
292
+ }
293
+ initializeAccounts(props) {
294
+ let { account } = props;
295
+ AccountService.listAccounts("dockerRegistry").then((allAccounts) => {
296
+ const accounts = allAccounts.map((a) => a.name);
297
+ if (this.props.showRegistry && !account) {
298
+ account = accounts[0];
299
+ }
300
+ this.accounts = accounts;
301
+ this.refreshImages({ ...props, ...{ account } });
302
+ });
303
+ }
304
+ isNew() {
305
+ const { account, organization, registry, repository, tag } = this.props;
306
+ return !account && !organization && !registry && !repository && !tag;
307
+ }
308
+ componentDidMount() {
309
+ if (!this.props.deferInitialization && (this.props.registry || this.isNew())) {
310
+ this.initializeAccounts(this.props);
311
+ }
312
+ }
313
+ valueChanged(name, value) {
314
+ const changes = { [name]: value };
315
+ if (imageFields$1.some((n) => n === name)) {
316
+ const { organization, repository, tag, digest } = this.props;
317
+ const imageParts = { ...{ organization, repository, tag, digest }, ...changes };
318
+ const imageId = DockerImageUtils.generateImageId(imageParts);
319
+ changes.imageId = imageId;
320
+ }
321
+ this.props.onChange && this.props.onChange(changes);
322
+ }
323
+ render() {
324
+ const {
325
+ account,
326
+ allowManualDefinition,
327
+ digest,
328
+ imageId,
329
+ organization,
330
+ repository,
331
+ showDigest,
332
+ showRegistry,
333
+ specifyTagByRegex,
334
+ tag
335
+ } = this.props;
336
+ const {
337
+ accountOptions,
338
+ switchedManualWarning,
339
+ missingFields,
340
+ imagesLoading,
341
+ lookupType,
342
+ organizationOptions,
343
+ repositoryOptions,
344
+ defineManually,
345
+ tagOptions
346
+ } = this.state;
347
+ const parsedImageId = DockerImageUtils.splitImageId(imageId);
348
+ const manualInputToggle = /* @__PURE__ */ React.createElement("div", {
349
+ className: "sp-formItem groupHeader"
350
+ }, /* @__PURE__ */ React.createElement("div", {
351
+ className: "sp-formItem__left"
352
+ }, /* @__PURE__ */ React.createElement("div", {
353
+ className: "sp-formLabel"
354
+ }, "Define Image ID"), /* @__PURE__ */ React.createElement("div", {
355
+ className: "sp-formActions sp-formActions--mobile"
356
+ }, /* @__PURE__ */ React.createElement("span", {
357
+ className: "action"
358
+ }))), /* @__PURE__ */ React.createElement("div", {
359
+ className: "sp-formItem__right"
360
+ }, /* @__PURE__ */ React.createElement("div", {
361
+ className: "sp-form"
362
+ }, /* @__PURE__ */ React.createElement("span", {
363
+ className: "field"
364
+ }, /* @__PURE__ */ React.createElement(Select, {
365
+ value: defineManually,
366
+ disabled: imagesLoading || !allowManualDefinition,
367
+ onChange: (o) => this.showManualInput(o.value),
368
+ options: defineOptions$1,
369
+ clearable: false
370
+ })))));
371
+ const warning = switchedManualWarning ? /* @__PURE__ */ React.createElement("div", {
372
+ className: "sp-formItem"
373
+ }, /* @__PURE__ */ React.createElement("div", {
374
+ className: "sp-formItem__left"
375
+ }), /* @__PURE__ */ React.createElement("div", {
376
+ className: "sp-formItem__right"
377
+ }, /* @__PURE__ */ React.createElement(ValidationMessage, {
378
+ type: "warning",
379
+ message: /* @__PURE__ */ React.createElement(React.Fragment, null, switchedManualWarning, (missingFields || []).map((f) => /* @__PURE__ */ React.createElement("div", {
380
+ key: f
381
+ }, /* @__PURE__ */ React.createElement(HelpField, {
382
+ expand: true,
383
+ id: `pipeline.config.docker.trigger.missing.${f}`
384
+ }))))
385
+ }))) : null;
386
+ if (defineManually) {
387
+ return /* @__PURE__ */ React.createElement("div", {
388
+ className: "sp-formGroup"
389
+ }, manualInputToggle, /* @__PURE__ */ React.createElement("div", {
390
+ className: "sp-formItem"
391
+ }, /* @__PURE__ */ React.createElement("div", {
392
+ className: "sp-formItem__left"
393
+ }, /* @__PURE__ */ React.createElement("div", {
394
+ className: "sp-formLabel"
395
+ }, "Image ID"), /* @__PURE__ */ React.createElement("div", {
396
+ className: "sp-formActions sp-formActions--mobile"
397
+ }, /* @__PURE__ */ React.createElement("span", {
398
+ className: "action"
399
+ }))), /* @__PURE__ */ React.createElement("div", {
400
+ className: "sp-formItem__right"
401
+ }, /* @__PURE__ */ React.createElement("div", {
402
+ className: "sp-form"
403
+ }, /* @__PURE__ */ React.createElement("span", {
404
+ className: "field"
405
+ }, /* @__PURE__ */ React.createElement("input", {
406
+ className: "form-control input-sm",
407
+ value: imageId || "",
408
+ onChange: (e) => this.valueChanged("imageId", e.target.value)
409
+ }))))), warning);
410
+ }
411
+ const Registry = showRegistry ? /* @__PURE__ */ React.createElement("div", {
412
+ className: "sp-formItem"
413
+ }, /* @__PURE__ */ React.createElement("div", {
414
+ className: "sp-formItem__left"
415
+ }, /* @__PURE__ */ React.createElement("div", {
416
+ className: "sp-formLabel"
417
+ }, "Registry Name")), /* @__PURE__ */ React.createElement("div", {
418
+ className: "sp-formItem__right"
419
+ }, /* @__PURE__ */ React.createElement("div", {
420
+ className: "sp-form"
421
+ }, /* @__PURE__ */ React.createElement("span", {
422
+ className: "field"
423
+ }, /* @__PURE__ */ React.createElement(Select, {
424
+ value: account,
425
+ disabled: imagesLoading,
426
+ onChange: (o) => this.valueChanged("account", o ? o.value : ""),
427
+ options: accountOptions,
428
+ isLoading: imagesLoading
429
+ })), /* @__PURE__ */ React.createElement("span", {
430
+ className: "sp-formActions sp-formActions--web"
431
+ }, /* @__PURE__ */ React.createElement("span", {
432
+ className: "action"
433
+ }, /* @__PURE__ */ React.createElement(Tooltip, {
434
+ value: imagesLoading ? "Images refreshing" : "Refresh images list"
435
+ }, /* @__PURE__ */ React.createElement("i", {
436
+ className: `fa icon-button-refresh-arrows ${imagesLoading ? "fa-spin" : ""}`,
437
+ onClick: this.handleRefreshImages
438
+ }))))))) : null;
439
+ const Organization = /* @__PURE__ */ React.createElement("div", {
440
+ className: "sp-formItem"
441
+ }, /* @__PURE__ */ React.createElement("div", {
442
+ className: "sp-formItem__left"
443
+ }, /* @__PURE__ */ React.createElement("div", {
444
+ className: "sp-formLabel"
445
+ }, "Organization")), /* @__PURE__ */ React.createElement("div", {
446
+ className: "sp-formItem__right"
447
+ }, /* @__PURE__ */ React.createElement("div", {
448
+ className: "sp-form"
449
+ }, /* @__PURE__ */ React.createElement("span", {
450
+ className: "field"
451
+ }, organization.includes("${") ? /* @__PURE__ */ React.createElement("input", {
452
+ disabled: imagesLoading,
453
+ className: "form-control input-sm",
454
+ value: organization || "",
455
+ onChange: (e) => this.valueChanged("organization", e.target.value)
456
+ }) : /* @__PURE__ */ React.createElement(Select, {
457
+ value: organization || "",
458
+ disabled: imagesLoading,
459
+ onChange: (o) => this.valueChanged("organization", o && o.value || ""),
460
+ placeholder: "No organization",
461
+ options: organizationOptions,
462
+ isLoading: imagesLoading
463
+ })))));
464
+ const Image = /* @__PURE__ */ React.createElement("div", {
465
+ className: "sp-formItem"
466
+ }, /* @__PURE__ */ React.createElement("div", {
467
+ className: "sp-formItem__left"
468
+ }, /* @__PURE__ */ React.createElement("div", {
469
+ className: "sp-formLabel"
470
+ }, "Image")), /* @__PURE__ */ React.createElement("div", {
471
+ className: "sp-formItem__right"
472
+ }, /* @__PURE__ */ React.createElement("div", {
473
+ className: "sp-form"
474
+ }, /* @__PURE__ */ React.createElement("span", {
475
+ className: "field"
476
+ }, repository.includes("${") ? /* @__PURE__ */ React.createElement("input", {
477
+ className: "form-control input-sm",
478
+ disabled: imagesLoading,
479
+ value: repository || "",
480
+ onChange: (e) => this.valueChanged("repository", e.target.value)
481
+ }) : /* @__PURE__ */ React.createElement(Select, {
482
+ value: repository || "",
483
+ disabled: imagesLoading,
484
+ onChange: (o) => this.valueChanged("repository", o && o.value || ""),
485
+ options: repositoryOptions,
486
+ required: true,
487
+ isLoading: imagesLoading
488
+ })))));
489
+ const Tag = lookupType === "tag" ? specifyTagByRegex ? /* @__PURE__ */ React.createElement("div", {
490
+ className: "sp-formItem"
491
+ }, /* @__PURE__ */ React.createElement("div", {
492
+ className: "sp-formItem__left"
493
+ }, /* @__PURE__ */ React.createElement("div", {
494
+ className: "sp-formLabel"
495
+ }, "Tag")), /* @__PURE__ */ React.createElement("div", {
496
+ className: "sp-formItem__right"
497
+ }, /* @__PURE__ */ React.createElement("div", {
498
+ className: "sp-form"
499
+ }, /* @__PURE__ */ React.createElement("span", {
500
+ className: "field"
501
+ }, /* @__PURE__ */ React.createElement("input", {
502
+ type: "text",
503
+ className: "form-control input-sm",
504
+ value: tag || "",
505
+ disabled: imagesLoading || !repository,
506
+ onChange: (e) => this.valueChanged("tag", e.target.value)
507
+ }))), /* @__PURE__ */ React.createElement(HelpField, {
508
+ id: "pipeline.config.docker.trigger.tag",
509
+ expand: true
510
+ }))) : /* @__PURE__ */ React.createElement("div", {
511
+ className: "sp-formItem"
512
+ }, /* @__PURE__ */ React.createElement("div", {
513
+ className: "sp-formItem__left"
514
+ }, /* @__PURE__ */ React.createElement("div", {
515
+ className: "sp-formLabel"
516
+ }, "Tag")), /* @__PURE__ */ React.createElement("div", {
517
+ className: "sp-formItem__right"
518
+ }, /* @__PURE__ */ React.createElement("div", {
519
+ className: "sp-form"
520
+ }, /* @__PURE__ */ React.createElement("span", {
521
+ className: "field"
522
+ }, tag && tag.includes("${") ? /* @__PURE__ */ React.createElement("input", {
523
+ className: "form-control input-sm",
524
+ disabled: imagesLoading,
525
+ value: tag || "",
526
+ onChange: (e) => this.valueChanged("tag", e.target.value),
527
+ required: true
528
+ }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Select, {
529
+ value: tag || "",
530
+ disabled: imagesLoading || !repository,
531
+ isLoading: imagesLoading,
532
+ onChange: (o) => this.valueChanged("tag", o ? o.value : void 0),
533
+ options: tagOptions,
534
+ placeholder: "No tag",
535
+ required: true
536
+ }), /* @__PURE__ */ React.createElement(HelpField, {
537
+ id: "pipeline.config.docker.trigger.tag.additionalInfo",
538
+ expand: true
539
+ })))))) : null;
540
+ const Digest = lookupType === "digest" ? /* @__PURE__ */ React.createElement("div", {
541
+ className: "sp-formItem"
542
+ }, /* @__PURE__ */ React.createElement("div", {
543
+ className: "sp-formItem__left"
544
+ }, /* @__PURE__ */ React.createElement("div", {
545
+ className: "sp-formLabel"
546
+ }, "Digest ", /* @__PURE__ */ React.createElement(HelpField, {
547
+ id: "pipeline.config.docker.trigger.digest"
548
+ }))), /* @__PURE__ */ React.createElement("div", {
549
+ className: "sp-formItem__right"
550
+ }, /* @__PURE__ */ React.createElement("div", {
551
+ className: "sp-form"
552
+ }, /* @__PURE__ */ React.createElement("span", {
553
+ className: "field"
554
+ }, /* @__PURE__ */ React.createElement("input", {
555
+ className: "form-control input-sm",
556
+ placeholder: "sha256:abc123",
557
+ value: digest || parsedImageId.digest || "",
558
+ onChange: (e) => this.valueChanged("digest", e.target.value),
559
+ required: true
560
+ }))))) : null;
561
+ const LookupTypeSelector = showDigest ? /* @__PURE__ */ React.createElement("div", {
562
+ className: "sp-formItem"
563
+ }, /* @__PURE__ */ React.createElement("div", {
564
+ className: "sp-formItem__left"
565
+ }, /* @__PURE__ */ React.createElement("div", {
566
+ className: "sp-formLabel"
567
+ }, "Type")), /* @__PURE__ */ React.createElement("div", {
568
+ className: "sp-formItem__right"
569
+ }, /* @__PURE__ */ React.createElement("div", {
570
+ className: "sp-form"
571
+ }, /* @__PURE__ */ React.createElement("span", {
572
+ className: "field"
573
+ }, /* @__PURE__ */ React.createElement(Select, {
574
+ clearable: false,
575
+ value: lookupType,
576
+ options: [
577
+ { value: "digest", label: "Digest" },
578
+ { value: "tag", label: "Tag" }
579
+ ],
580
+ onChange: this.lookupTypeChanged
581
+ }))))) : null;
582
+ return /* @__PURE__ */ React.createElement("div", {
583
+ className: "sp-formGroup"
584
+ }, manualInputToggle, Registry, Organization, Image, LookupTypeSelector, Digest, Tag);
585
+ }
586
+ }
587
+ DockerImageAndTagSelector.defaultProps = {
588
+ organization: "",
589
+ registry: "",
590
+ repository: "",
591
+ showDigest: true,
592
+ allowManualDefinition: true
593
+ };
594
+
595
+ const DOCKER_PIPELINE_STAGES_BAKE_BAKEEXECUTIONDETAILS_CONTROLLER = "spinnaker.docker.pipeline.stage.bake.executionDetails.controller";
596
+ module(DOCKER_PIPELINE_STAGES_BAKE_BAKEEXECUTIONDETAILS_CONTROLLER, [UIROUTER_ANGULARJS]).controller("dockerBakeExecutionDetailsCtrl", [
597
+ "$scope",
598
+ "$stateParams",
599
+ "executionDetailsSectionService",
600
+ "$interpolate",
601
+ function($scope, $stateParams, executionDetailsSectionService, $interpolate) {
602
+ $scope.configSections = ["bakeConfig", "taskStatus"];
603
+ const initialized = () => {
604
+ $scope.detailsSection = $stateParams.details;
605
+ $scope.provider = $scope.stage.context.cloudProviderType || "docker";
606
+ $scope.bakeryDetailUrl = $interpolate($scope.roscoMode && SETTINGS.roscoDetailUrl ? SETTINGS.roscoDetailUrl : SETTINGS.bakeryDetailUrl);
607
+ };
608
+ const initialize = () => executionDetailsSectionService.synchronizeSection($scope.configSections, initialized);
609
+ initialize();
610
+ $scope.$on("$stateChangeSuccess", initialize);
611
+ }
612
+ ]);
613
+
614
+ const DOCKER_PIPELINE_STAGES_BAKE_DOCKERBAKESTAGE = "spinnaker.docker.pipeline.stage.bakeStage";
615
+ module(DOCKER_PIPELINE_STAGES_BAKE_DOCKERBAKESTAGE, [DOCKER_PIPELINE_STAGES_BAKE_BAKEEXECUTIONDETAILS_CONTROLLER]).config(function() {
616
+ Registry.pipeline.registerStage({
617
+ provides: "bake",
618
+ cloudProvider: "docker",
619
+ label: "Bake",
620
+ description: "Bakes an image",
621
+ templateUrl: "docker/src/pipeline/stages/bake/bakeStage.html",
622
+ executionDetailsUrl: "docker/src/pipeline/stages/bake/bakeExecutionDetails.html",
623
+ executionLabelComponent: BakeExecutionLabel,
624
+ extraLabelLines: (stage) => {
625
+ return stage.masterStage.context.allPreviouslyBaked || stage.masterStage.context.somePreviouslyBaked ? 1 : 0;
626
+ },
627
+ supportsCustomTimeout: true,
628
+ validators: [{ type: "requiredField", fieldName: "package" }],
629
+ restartable: true
630
+ });
631
+ }).controller("dockerBakeStageCtrl", [
632
+ "$scope",
633
+ "$q",
634
+ function($scope, $q) {
635
+ const stage = $scope.stage;
636
+ stage.region = "global";
637
+ if (!$scope.stage.user) {
638
+ $scope.stage.user = AuthenticationService.getAuthenticatedUser().name;
639
+ }
640
+ $scope.viewState = {
641
+ loading: true
642
+ };
643
+ function initialize() {
644
+ $scope.viewState.providerSelected = true;
645
+ $q.all([BakeryReader.getBaseOsOptions("docker"), BakeryReader.getBaseLabelOptions()]).then(function([
646
+ baseOsOptions,
647
+ baseLabelOptions
648
+ ]) {
649
+ $scope.baseOsOptions = baseOsOptions.baseImages;
650
+ $scope.baseLabelOptions = baseLabelOptions;
651
+ if (!$scope.stage.baseOs && $scope.baseOsOptions && $scope.baseOsOptions.length) {
652
+ $scope.stage.baseOs = $scope.baseOsOptions[0].id;
653
+ }
654
+ if (!$scope.stage.baseLabel && $scope.baseLabelOptions && $scope.baseLabelOptions.length) {
655
+ $scope.stage.baseLabel = $scope.baseLabelOptions[0];
656
+ }
657
+ $scope.viewState.loading = false;
658
+ });
659
+ }
660
+ function deleteEmptyProperties() {
661
+ _.forOwn($scope.stage, function(val, key) {
662
+ if (val === "") {
663
+ delete $scope.stage[key];
664
+ }
665
+ });
666
+ }
667
+ $scope.$watch("stage", deleteEmptyProperties, true);
668
+ initialize();
669
+ }
670
+ ]);
671
+ window.angular.module("ng").run(["$templateCache", function(templateCache) {
672
+ templateCache.put("docker/src/pipeline/stages/bake/bakeStage.html", `<div ng-controller="dockerBakeStageCtrl as bakeStageCtrl">
673
+ <stage-config-field label="Package" help-key="pipeline.config.bake.package">
674
+ <input type="text" class="form-control input-sm" ng-model="stage.package" />
675
+ </stage-config-field>
676
+ <stage-config-field label="Organization" help-key="pipeline.config.docker.bake.organization">
677
+ <input type="text" class="form-control input-sm" ng-model="stage.organization" />
678
+ </stage-config-field>
679
+ <stage-config-field label="Image Name" help-key="pipeline.config.docker.bake.targetImage">
680
+ <input type="text" class="form-control input-sm" ng-model="stage.ami_name" />
681
+ </stage-config-field>
682
+ <stage-config-field label="Image tag" help-key="pipeline.config.docker.bake.targetImageTag">
683
+ <input type="text" class="form-control input-sm" ng-model="stage.extendedAttributes['docker_target_image_tag']" />
684
+ </stage-config-field>
685
+ <stage-config-field label="Base OS">
686
+ <bake-stage-choose-os model="stage.baseOs" base-os-options="baseOsOptions"></bake-stage-choose-os>
687
+ </stage-config-field>
688
+
689
+ <stage-config-field label="Base Label">
690
+ <label class="radio-inline" ng-repeat="baseLabel in baseLabelOptions">
691
+ <input type="radio" ng-model="stage.baseLabel" ng-value="baseLabel" />
692
+ {{baseLabel}}
693
+ </label>
694
+ </stage-config-field>
695
+ <stage-config-field label="Rebake">
696
+ <div class="checkbox" style="margin-bottom: 0">
697
+ <label>
698
+ <input type="checkbox" ng-model="stage.rebake" />
699
+ Rebake image without regard to the status of any existing bake
700
+ </label>
701
+ </div>
702
+ </stage-config-field>
703
+ </div>
704
+ `);
705
+ }]);
706
+ window.angular.module("ng").run(["$templateCache", function(templateCache) {
707
+ templateCache.put("docker/src/pipeline/stages/bake/bakeExecutionDetails.html", `<div ng-controller="dockerBakeExecutionDetailsCtrl">
708
+ <execution-details-section-nav sections="configSections"></execution-details-section-nav>
709
+ <div class="step-section-details" ng-if="detailsSection === 'bakeConfig'">
710
+ <div class="row">
711
+ <div class="col-md-6">
712
+ <dl class="dl-narrow dl-horizontal">
713
+ <dt if-multiple-providers>Provider</dt>
714
+ <dd if-multiple-providers>Docker</dd>
715
+ <dt>Organization</dt>
716
+ <dd>{{stage.context.organization}}</dd>
717
+ <dt>Image Name</dt>
718
+ <dd>{{stage.context.ami_name}}</dd>
719
+ <dt>Image Tag</dt>
720
+ <dd>{{stage.context.extendedAttributes['docker_target_image_tag']}}</dd>
721
+ <dt>Image</dt>
722
+ <dd>{{stage.context.ami}}</dd>
723
+ </dl>
724
+ </div>
725
+ <div class="col-md-6">
726
+ <dl class="dl-narrow dl-horizontal">
727
+ <dt>Base OS</dt>
728
+ <dd>{{stage.context.baseOs}}</dd>
729
+ <dt>Region</dt>
730
+ <dd>{{stage.context.region}}</dd>
731
+ <dt>Package</dt>
732
+ <dd>{{stage.context.package}}</dd>
733
+ <dt>Label</dt>
734
+ <dd>{{stage.context.baseLabel}}</dd>
735
+ </dl>
736
+ </div>
737
+ </div>
738
+ <stage-failure-message stage="stage" message="stage.failureMessage"></stage-failure-message>
739
+
740
+ <div class="row" ng-if="stage.context.region && stage.context.status.resourceId">
741
+ <div class="col-md-12">
742
+ <div class="alert alert-{{stage.isFailed ? 'danger' : 'info'}}">
743
+ <a target="_blank" href="{{ bakeryDetailUrl(stage) }}"> View Bakery Details </a>
744
+ </div>
745
+ </div>
746
+ </div>
747
+ </div>
748
+ <div class="step-section-details" ng-if="detailsSection === 'taskStatus'">
749
+ <div class="row">
750
+ <execution-step-details item="stage"></execution-step-details>
751
+ </div>
752
+ </div>
753
+ </div>
754
+ `);
755
+ }]);
756
+
757
+ const imageFields = ["organization", "repository", "tag", "digest"];
758
+ const defineOptions = [
759
+ { label: "Manually", value: true },
760
+ { label: "Select from list", value: false }
761
+ ];
762
+ class DockerChartAndTagSelector extends React.Component {
763
+ constructor(props) {
764
+ super(props);
765
+ this.unmounted = false;
766
+ this.cachedValues = {};
767
+ this.handleRefreshImages = () => {
768
+ this.refreshImages(this.props);
769
+ };
770
+ this.lookupTypeChanged = (o) => {
771
+ const newType = o.value;
772
+ const oldType = this.state.lookupType;
773
+ const oldValue = this.props[oldType];
774
+ const cachedValue = this.cachedValues[newType];
775
+ this.valueChanged(oldType, void 0);
776
+ if (this.cachedValues[newType]) {
777
+ this.valueChanged(newType, cachedValue);
778
+ }
779
+ this.setState({ lookupType: newType });
780
+ this.cachedValues[oldType] = oldValue;
781
+ };
782
+ this.showManualInput = (defineManually) => {
783
+ if (!defineManually) {
784
+ const newFields = DockerImageUtils.splitImageId(this.props.imageId || "");
785
+ this.props.onChange(newFields);
786
+ if (this.state.switchedManualWarning) {
787
+ this.setState({ switchedManualWarning: void 0, missingFields: void 0 });
788
+ }
789
+ }
790
+ this.setState({ defineManually });
791
+ };
792
+ const accountOptions = props.account ? [{ label: props.account, value: props.account }] : [];
793
+ const organizationOptions = props.organization && props.organization.length ? [{ label: props.organization, value: props.organization }] : [];
794
+ const repositoryOptions = props.repository && props.repository.length ? [{ label: props.repository, value: props.repository }] : [];
795
+ const tagOptions = props.tag && props.tag.length ? [{ label: props.tag, value: props.tag }] : [];
796
+ const parsedImageId = DockerImageUtils.splitImageId(props.imageId);
797
+ const defineManually = props.allowManualDefinition && Boolean(props.imageId && props.imageId.includes("${"));
798
+ this.state = {
799
+ accountOptions,
800
+ switchedManualWarning: void 0,
801
+ imagesLoaded: false,
802
+ imagesLoading: false,
803
+ organizationOptions,
804
+ repositoryOptions,
805
+ defineManually,
806
+ tagOptions,
807
+ lookupType: props.digest || parsedImageId.digest ? "digest" : "tag"
808
+ };
809
+ }
810
+ getAccountMap(images) {
811
+ const groupedImages = groupBy(images.filter((image) => image.account), "account");
812
+ return reduce(groupedImages, (acc, image, key) => {
813
+ acc[key] = uniq(image.map((i) => `${i.repository.split("/").slice(0, -1).join("/")}`));
814
+ return acc;
815
+ }, {});
816
+ }
817
+ getRegistryMap(images) {
818
+ return images.reduce((m, image) => {
819
+ m[image.account] = image.registry;
820
+ return m;
821
+ }, {});
822
+ }
823
+ getOrganizationMap(images) {
824
+ const extractGroupByKey = (image) => `${image.account}/${image.repository.split("/").slice(0, -1).join("/")}`;
825
+ const groupedImages = groupBy(images.filter((image) => image.repository), extractGroupByKey);
826
+ return reduce(groupedImages, (acc, image, key) => {
827
+ acc[key] = uniq(image.map((i) => i.repository));
828
+ return acc;
829
+ }, {});
830
+ }
831
+ getRepositoryMap(images) {
832
+ const groupedImages = groupBy(images.filter((image) => image.account), "repository");
833
+ return reduce(groupedImages, (acc, image, key) => {
834
+ acc[key] = uniq(image.map((i) => i.tag));
835
+ return acc;
836
+ }, {});
837
+ }
838
+ getOrganizationsList(accountMap) {
839
+ return accountMap ? accountMap[this.props.showRegistry ? this.props.account : this.props.registry] || [] : [];
840
+ }
841
+ getRepositoryList(organizationMap, organization, registry) {
842
+ if (organizationMap) {
843
+ const key = `${this.props.showRegistry ? this.props.account : registry}/${organization || ""}`;
844
+ return organizationMap[key] || [];
845
+ }
846
+ return [];
847
+ }
848
+ getTags(tag, repositoryMap, repository) {
849
+ let tags = [];
850
+ if (this.props.specifyTagByRegex) {
851
+ if (tag && trim(tag) === "") {
852
+ tag = void 0;
853
+ }
854
+ } else {
855
+ if (repositoryMap) {
856
+ tags = repositoryMap[repository] || [];
857
+ if (!tags.includes(tag) && tag && !tag.includes("${")) {
858
+ tag = void 0;
859
+ }
860
+ }
861
+ }
862
+ return { tag, tags };
863
+ }
864
+ componentWillReceiveProps(nextProps) {
865
+ if (!this.images || ["account", "showRegistry"].some((key) => this.props[key] !== nextProps[key])) {
866
+ this.refreshImages(nextProps);
867
+ } else if (["organization", "registry", "repository"].some((key) => this.props[key] !== nextProps[key])) {
868
+ this.updateThings(nextProps);
869
+ }
870
+ if (nextProps.imageId && nextProps.imageId.includes("${")) {
871
+ this.setState({ defineManually: true });
872
+ }
873
+ }
874
+ componentWillUnmount() {
875
+ this.unmounted = true;
876
+ }
877
+ synchronizeChanges(values, registry) {
878
+ const { organization, repository, tag, digest } = values;
879
+ if (this.props.onChange) {
880
+ const imageId = DockerImageUtils.generateImageId({ organization, repository, tag, digest });
881
+ const changes = {};
882
+ if (tag !== this.props.tag) {
883
+ changes.tag = tag;
884
+ }
885
+ if (imageId !== this.props.imageId) {
886
+ changes.imageId = imageId;
887
+ }
888
+ if (organization !== this.props.organization) {
889
+ changes.organization = organization;
890
+ }
891
+ if (registry !== this.props.registry) {
892
+ changes.registry = registry;
893
+ }
894
+ if (repository !== this.props.repository) {
895
+ changes.repository = repository;
896
+ }
897
+ if (digest !== this.props.digest) {
898
+ changes.digest = digest;
899
+ }
900
+ if (Object.keys(changes).length > 0) {
901
+ this.props.onChange(changes);
902
+ }
903
+ }
904
+ }
905
+ updateThings(props, allowAutoSwitchToManualEntry = false) {
906
+ if (!this.repositoryMap || this.unmounted) {
907
+ return;
908
+ }
909
+ const { imageId, specifyTagByRegex } = props;
910
+ let { organization, registry, repository } = props;
911
+ if (props.showRegistry) {
912
+ registry = this.registryMap[props.account];
913
+ }
914
+ const organizationFound = !organization || this.organizations.includes(organization) || organization.includes("${");
915
+ if (!organizationFound) {
916
+ organization = "";
917
+ }
918
+ const repositories = this.getRepositoryList(this.organizationMap, organization, registry);
919
+ const repositoryFound = !repository || repository.includes("${") || repositories.includes(repository);
920
+ if (!repositoryFound) {
921
+ repository = "";
922
+ }
923
+ const { tag, tags } = this.getTags(props.tag, this.repositoryMap, repository);
924
+ const tagFound = tag === props.tag || specifyTagByRegex;
925
+ const newState = {
926
+ accountOptions: this.newAccounts.sort().map((a) => ({ label: a, value: a })),
927
+ organizationOptions: this.organizations.filter((o) => o).sort().map((o) => ({ label: o, value: o })),
928
+ imagesLoaded: true,
929
+ repositoryOptions: repositories.sort().map((r) => ({ label: r, value: r })),
930
+ tagOptions: tags.sort().map((t) => ({ label: t, value: t }))
931
+ };
932
+ if (imageId && (!this.state.imagesLoaded || allowAutoSwitchToManualEntry) && (!organizationFound || !repositoryFound || !tagFound)) {
933
+ newState.defineManually = true;
934
+ const missingFields = [];
935
+ if (!organizationFound) {
936
+ missingFields.push("organization");
937
+ }
938
+ if (!repositoryFound) {
939
+ missingFields.push("image");
940
+ }
941
+ if (!tagFound) {
942
+ missingFields.push("tag");
943
+ }
944
+ newState.missingFields = missingFields;
945
+ newState.switchedManualWarning = `Could not find ${missingFields.join(" or ")}, switched to manual entry`;
946
+ } else if (!imageId || !imageId.includes("${")) {
947
+ this.synchronizeChanges(this.state.defineManually ? DockerImageUtils.splitImageId(imageId) : { organization, repository, tag, digest: this.props.digest }, registry);
948
+ }
949
+ this.setState(newState);
950
+ }
951
+ initializeImages(props) {
952
+ if (this.state.imagesLoading) {
953
+ return;
954
+ }
955
+ const { showRegistry, account, registry } = props;
956
+ const imageConfig = {
957
+ provider: "dockerRegistry",
958
+ account: showRegistry ? account : registry
959
+ };
960
+ this.setState({ imagesLoading: true });
961
+ DockerChartImageReader.findImages(imageConfig).then((images) => {
962
+ this.images = images;
963
+ this.registryMap = this.getRegistryMap(this.images);
964
+ this.accountMap = this.getAccountMap(this.images);
965
+ this.newAccounts = this.accounts || Object.keys(this.accountMap);
966
+ this.organizationMap = this.getOrganizationMap(this.images);
967
+ this.repositoryMap = this.getRepositoryMap(this.images);
968
+ this.organizations = this.getOrganizationsList(this.accountMap);
969
+ this.updateThings(props, true);
970
+ }).finally(() => {
971
+ if (!this.unmounted) {
972
+ this.setState({ imagesLoading: false });
973
+ }
974
+ });
975
+ }
976
+ refreshImages(props) {
977
+ this.initializeImages(props);
978
+ }
979
+ initializeAccounts(props) {
980
+ let { account } = props;
981
+ AccountService.listAccounts("dockerRegistry").then((allAccounts) => {
982
+ const accounts = allAccounts.map((a) => a.name);
983
+ if (this.props.showRegistry && !account) {
984
+ account = accounts[0];
985
+ }
986
+ this.accounts = accounts;
987
+ this.refreshImages({ ...props, ...{ account } });
988
+ });
989
+ }
990
+ isNew() {
991
+ const { account, organization, registry, repository, tag } = this.props;
992
+ return !account && !organization && !registry && !repository && !tag;
993
+ }
994
+ componentDidMount() {
995
+ if (!this.props.deferInitialization && (this.props.registry || this.isNew())) {
996
+ this.initializeAccounts(this.props);
997
+ }
998
+ }
999
+ valueChanged(name, value) {
1000
+ const changes = { [name]: value };
1001
+ if (imageFields.some((n) => n === name)) {
1002
+ const { organization, repository, tag, digest } = this.props;
1003
+ const imageParts = { ...{ organization, repository, tag, digest }, ...changes };
1004
+ const imageId = DockerImageUtils.generateImageId(imageParts);
1005
+ changes.imageId = imageId;
1006
+ }
1007
+ this.props.onChange && this.props.onChange(changes);
1008
+ }
1009
+ render() {
1010
+ const {
1011
+ account,
1012
+ allowManualDefinition,
1013
+ digest,
1014
+ imageId,
1015
+ organization,
1016
+ repository,
1017
+ showDigest,
1018
+ showRegistry,
1019
+ specifyTagByRegex,
1020
+ tag
1021
+ } = this.props;
1022
+ const {
1023
+ accountOptions,
1024
+ switchedManualWarning,
1025
+ missingFields,
1026
+ imagesLoading,
1027
+ lookupType,
1028
+ organizationOptions,
1029
+ repositoryOptions,
1030
+ defineManually,
1031
+ tagOptions
1032
+ } = this.state;
1033
+ const parsedImageId = DockerImageUtils.splitImageId(imageId);
1034
+ const manualInputToggle = /* @__PURE__ */ React.createElement("div", {
1035
+ className: "sp-formItem groupHeader"
1036
+ }, /* @__PURE__ */ React.createElement("div", {
1037
+ className: "sp-formItem__left"
1038
+ }, /* @__PURE__ */ React.createElement("div", {
1039
+ className: "sp-formLabel"
1040
+ }, "Define Image ID"), /* @__PURE__ */ React.createElement("div", {
1041
+ className: "sp-formActions sp-formActions--mobile"
1042
+ }, /* @__PURE__ */ React.createElement("span", {
1043
+ className: "action"
1044
+ }))), /* @__PURE__ */ React.createElement("div", {
1045
+ className: "sp-formItem__right"
1046
+ }, /* @__PURE__ */ React.createElement("div", {
1047
+ className: "sp-form"
1048
+ }, /* @__PURE__ */ React.createElement("span", {
1049
+ className: "field"
1050
+ }, /* @__PURE__ */ React.createElement(Select, {
1051
+ value: defineManually,
1052
+ disabled: imagesLoading || !allowManualDefinition,
1053
+ onChange: (o) => this.showManualInput(o.value),
1054
+ options: defineOptions,
1055
+ clearable: false
1056
+ })))));
1057
+ const warning = switchedManualWarning ? /* @__PURE__ */ React.createElement("div", {
1058
+ className: "sp-formItem"
1059
+ }, /* @__PURE__ */ React.createElement("div", {
1060
+ className: "sp-formItem__left"
1061
+ }), /* @__PURE__ */ React.createElement("div", {
1062
+ className: "sp-formItem__right"
1063
+ }, /* @__PURE__ */ React.createElement(ValidationMessage, {
1064
+ type: "warning",
1065
+ message: /* @__PURE__ */ React.createElement(React.Fragment, null, switchedManualWarning, (missingFields || []).map((f) => /* @__PURE__ */ React.createElement("div", {
1066
+ key: f
1067
+ }, /* @__PURE__ */ React.createElement(HelpField, {
1068
+ expand: true,
1069
+ id: `pipeline.config.docker.trigger.missing.${f}`
1070
+ }))))
1071
+ }))) : null;
1072
+ if (defineManually) {
1073
+ return /* @__PURE__ */ React.createElement("div", {
1074
+ className: "sp-formGroup"
1075
+ }, manualInputToggle, /* @__PURE__ */ React.createElement("div", {
1076
+ className: "sp-formItem"
1077
+ }, /* @__PURE__ */ React.createElement("div", {
1078
+ className: "sp-formItem__left"
1079
+ }, /* @__PURE__ */ React.createElement("div", {
1080
+ className: "sp-formLabel"
1081
+ }, "Image ID"), /* @__PURE__ */ React.createElement("div", {
1082
+ className: "sp-formActions sp-formActions--mobile"
1083
+ }, /* @__PURE__ */ React.createElement("span", {
1084
+ className: "action"
1085
+ }))), /* @__PURE__ */ React.createElement("div", {
1086
+ className: "sp-formItem__right"
1087
+ }, /* @__PURE__ */ React.createElement("div", {
1088
+ className: "sp-form"
1089
+ }, /* @__PURE__ */ React.createElement("span", {
1090
+ className: "field"
1091
+ }, /* @__PURE__ */ React.createElement("input", {
1092
+ className: "form-control input-sm",
1093
+ value: imageId || "",
1094
+ onChange: (e) => this.valueChanged("imageId", e.target.value)
1095
+ }))))), warning);
1096
+ }
1097
+ const Registry = showRegistry ? /* @__PURE__ */ React.createElement("div", {
1098
+ className: "sp-formItem"
1099
+ }, /* @__PURE__ */ React.createElement("div", {
1100
+ className: "sp-formItem__left"
1101
+ }, /* @__PURE__ */ React.createElement("div", {
1102
+ className: "sp-formLabel"
1103
+ }, "Registry Name")), /* @__PURE__ */ React.createElement("div", {
1104
+ className: "sp-formItem__right"
1105
+ }, /* @__PURE__ */ React.createElement("div", {
1106
+ className: "sp-form"
1107
+ }, /* @__PURE__ */ React.createElement("span", {
1108
+ className: "field"
1109
+ }, /* @__PURE__ */ React.createElement(Select, {
1110
+ value: account,
1111
+ disabled: imagesLoading,
1112
+ onChange: (o) => this.valueChanged("account", o ? o.value : ""),
1113
+ options: accountOptions,
1114
+ isLoading: imagesLoading
1115
+ })), /* @__PURE__ */ React.createElement("span", {
1116
+ className: "sp-formActions sp-formActions--web"
1117
+ }, /* @__PURE__ */ React.createElement("span", {
1118
+ className: "action"
1119
+ }, /* @__PURE__ */ React.createElement(Tooltip, {
1120
+ value: imagesLoading ? "Images refreshing" : "Refresh images list"
1121
+ }, /* @__PURE__ */ React.createElement("i", {
1122
+ className: `fa icon-button-refresh-arrows ${imagesLoading ? "fa-spin" : ""}`,
1123
+ onClick: this.handleRefreshImages
1124
+ }))))))) : null;
1125
+ const Organization = /* @__PURE__ */ React.createElement("div", {
1126
+ className: "sp-formItem"
1127
+ }, /* @__PURE__ */ React.createElement("div", {
1128
+ className: "sp-formItem__left"
1129
+ }, /* @__PURE__ */ React.createElement("div", {
1130
+ className: "sp-formLabel"
1131
+ }, "Organization")), /* @__PURE__ */ React.createElement("div", {
1132
+ className: "sp-formItem__right"
1133
+ }, /* @__PURE__ */ React.createElement("div", {
1134
+ className: "sp-form"
1135
+ }, /* @__PURE__ */ React.createElement("span", {
1136
+ className: "field"
1137
+ }, organization.includes("${") ? /* @__PURE__ */ React.createElement("input", {
1138
+ disabled: imagesLoading,
1139
+ className: "form-control input-sm",
1140
+ value: organization || "",
1141
+ onChange: (e) => this.valueChanged("organization", e.target.value)
1142
+ }) : /* @__PURE__ */ React.createElement(Select, {
1143
+ value: organization || "",
1144
+ disabled: imagesLoading,
1145
+ onChange: (o) => this.valueChanged("organization", o && o.value || ""),
1146
+ placeholder: "No organization",
1147
+ options: organizationOptions,
1148
+ isLoading: imagesLoading
1149
+ })))));
1150
+ const Image = /* @__PURE__ */ React.createElement("div", {
1151
+ className: "sp-formItem"
1152
+ }, /* @__PURE__ */ React.createElement("div", {
1153
+ className: "sp-formItem__left"
1154
+ }, /* @__PURE__ */ React.createElement("div", {
1155
+ className: "sp-formLabel"
1156
+ }, "Image")), /* @__PURE__ */ React.createElement("div", {
1157
+ className: "sp-formItem__right"
1158
+ }, /* @__PURE__ */ React.createElement("div", {
1159
+ className: "sp-form"
1160
+ }, /* @__PURE__ */ React.createElement("span", {
1161
+ className: "field"
1162
+ }, repository.includes("${") ? /* @__PURE__ */ React.createElement("input", {
1163
+ className: "form-control input-sm",
1164
+ disabled: imagesLoading,
1165
+ value: repository || "",
1166
+ onChange: (e) => this.valueChanged("repository", e.target.value)
1167
+ }) : /* @__PURE__ */ React.createElement(Select, {
1168
+ value: repository || "",
1169
+ disabled: imagesLoading,
1170
+ onChange: (o) => this.valueChanged("repository", o && o.value || ""),
1171
+ options: repositoryOptions,
1172
+ required: true,
1173
+ isLoading: imagesLoading
1174
+ })))));
1175
+ const Tag = lookupType === "tag" ? specifyTagByRegex ? /* @__PURE__ */ React.createElement("div", {
1176
+ className: "sp-formItem"
1177
+ }, /* @__PURE__ */ React.createElement("div", {
1178
+ className: "sp-formItem__left"
1179
+ }, /* @__PURE__ */ React.createElement("div", {
1180
+ className: "sp-formLabel"
1181
+ }, "Tag")), /* @__PURE__ */ React.createElement("div", {
1182
+ className: "sp-formItem__right"
1183
+ }, /* @__PURE__ */ React.createElement("div", {
1184
+ className: "sp-form"
1185
+ }, /* @__PURE__ */ React.createElement("span", {
1186
+ className: "field"
1187
+ }, /* @__PURE__ */ React.createElement("input", {
1188
+ type: "text",
1189
+ className: "form-control input-sm",
1190
+ value: tag || "",
1191
+ disabled: imagesLoading || !repository,
1192
+ onChange: (e) => this.valueChanged("tag", e.target.value)
1193
+ }))), /* @__PURE__ */ React.createElement(HelpField, {
1194
+ id: "pipeline.config.docker.trigger.tag",
1195
+ expand: true
1196
+ }))) : /* @__PURE__ */ React.createElement("div", {
1197
+ className: "sp-formItem"
1198
+ }, /* @__PURE__ */ React.createElement("div", {
1199
+ className: "sp-formItem__left"
1200
+ }, /* @__PURE__ */ React.createElement("div", {
1201
+ className: "sp-formLabel"
1202
+ }, "Tag")), /* @__PURE__ */ React.createElement("div", {
1203
+ className: "sp-formItem__right"
1204
+ }, /* @__PURE__ */ React.createElement("div", {
1205
+ className: "sp-form"
1206
+ }, /* @__PURE__ */ React.createElement("span", {
1207
+ className: "field"
1208
+ }, tag && tag.includes("${") ? /* @__PURE__ */ React.createElement("input", {
1209
+ className: "form-control input-sm",
1210
+ disabled: imagesLoading,
1211
+ value: tag || "",
1212
+ onChange: (e) => this.valueChanged("tag", e.target.value),
1213
+ required: true
1214
+ }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Select, {
1215
+ value: tag || "",
1216
+ disabled: imagesLoading || !repository,
1217
+ isLoading: imagesLoading,
1218
+ onChange: (o) => this.valueChanged("tag", o ? o.value : void 0),
1219
+ options: tagOptions,
1220
+ placeholder: "No tag",
1221
+ required: true
1222
+ }), /* @__PURE__ */ React.createElement(HelpField, {
1223
+ id: "pipeline.config.docker.trigger.tag.additionalInfo",
1224
+ expand: true
1225
+ })))))) : null;
1226
+ const Digest = lookupType === "digest" ? /* @__PURE__ */ React.createElement("div", {
1227
+ className: "sp-formItem"
1228
+ }, /* @__PURE__ */ React.createElement("div", {
1229
+ className: "sp-formItem__left"
1230
+ }, /* @__PURE__ */ React.createElement("div", {
1231
+ className: "sp-formLabel"
1232
+ }, "Digest ", /* @__PURE__ */ React.createElement(HelpField, {
1233
+ id: "pipeline.config.docker.trigger.digest"
1234
+ }))), /* @__PURE__ */ React.createElement("div", {
1235
+ className: "sp-formItem__right"
1236
+ }, /* @__PURE__ */ React.createElement("div", {
1237
+ className: "sp-form"
1238
+ }, /* @__PURE__ */ React.createElement("span", {
1239
+ className: "field"
1240
+ }, /* @__PURE__ */ React.createElement("input", {
1241
+ className: "form-control input-sm",
1242
+ placeholder: "sha256:abc123",
1243
+ value: digest || parsedImageId.digest || "",
1244
+ onChange: (e) => this.valueChanged("digest", e.target.value),
1245
+ required: true
1246
+ }))))) : null;
1247
+ const LookupTypeSelector = showDigest ? /* @__PURE__ */ React.createElement("div", {
1248
+ className: "sp-formItem"
1249
+ }, /* @__PURE__ */ React.createElement("div", {
1250
+ className: "sp-formItem__left"
1251
+ }, /* @__PURE__ */ React.createElement("div", {
1252
+ className: "sp-formLabel"
1253
+ }, "Type")), /* @__PURE__ */ React.createElement("div", {
1254
+ className: "sp-formItem__right"
1255
+ }, /* @__PURE__ */ React.createElement("div", {
1256
+ className: "sp-form"
1257
+ }, /* @__PURE__ */ React.createElement("span", {
1258
+ className: "field"
1259
+ }, /* @__PURE__ */ React.createElement(Select, {
1260
+ clearable: false,
1261
+ value: lookupType,
1262
+ options: [
1263
+ { value: "digest", label: "Digest" },
1264
+ { value: "tag", label: "Tag" }
1265
+ ],
1266
+ onChange: this.lookupTypeChanged
1267
+ }))))) : null;
1268
+ return /* @__PURE__ */ React.createElement("div", {
1269
+ className: "sp-formGroup"
1270
+ }, manualInputToggle, Registry, Organization, Image, LookupTypeSelector, Digest, Tag);
1271
+ }
1272
+ }
1273
+ DockerChartAndTagSelector.defaultProps = {
1274
+ organization: "",
1275
+ registry: "",
1276
+ repository: "",
1277
+ showDigest: true,
1278
+ allowManualDefinition: true
1279
+ };
1280
+
1281
+ function DockerHelmOciTriggerConfig(props) {
1282
+ const { formik } = props;
1283
+ const trigger = formik.values;
1284
+ const dockerChanged = (changes) => {
1285
+ const { imageId, ...rest } = changes;
1286
+ props.triggerUpdated(rest);
1287
+ };
1288
+ return /* @__PURE__ */ React.createElement("div", {
1289
+ className: "form-horizontal"
1290
+ }, /* @__PURE__ */ React.createElement(DockerChartAndTagSelector, {
1291
+ allowManualDefinition: false,
1292
+ specifyTagByRegex: true,
1293
+ account: trigger.account,
1294
+ organization: trigger.organization,
1295
+ registry: trigger.registry,
1296
+ repository: trigger.repository,
1297
+ tag: trigger.tag,
1298
+ showRegistry: true,
1299
+ onChange: dockerChanged,
1300
+ showDigest: false
1301
+ }));
1302
+ }
1303
+
1304
+ function DockerTriggerConfig(props) {
1305
+ const { formik } = props;
1306
+ const trigger = formik.values;
1307
+ const dockerChanged = (changes) => {
1308
+ const { imageId, ...rest } = changes;
1309
+ props.triggerUpdated(rest);
1310
+ };
1311
+ return /* @__PURE__ */ React.createElement("div", {
1312
+ className: "form-horizontal"
1313
+ }, /* @__PURE__ */ React.createElement(DockerImageAndTagSelector, {
1314
+ allowManualDefinition: false,
1315
+ specifyTagByRegex: true,
1316
+ account: trigger.account,
1317
+ organization: trigger.organization,
1318
+ registry: trigger.registry,
1319
+ repository: trigger.repository,
1320
+ tag: trigger.tag,
1321
+ showRegistry: true,
1322
+ onChange: dockerChanged,
1323
+ showDigest: false
1324
+ }));
1325
+ }
1326
+
1327
+ const lookupTypeOptions = [
1328
+ { value: "digest", label: "Digest" },
1329
+ { value: "tag", label: "Tag" }
1330
+ ];
1331
+ class DockerTriggerTemplate extends React.Component {
1332
+ constructor(props) {
1333
+ super(props);
1334
+ this.queryStream = new Subject();
1335
+ this.handleQuery = () => {
1336
+ const trigger = this.props.command.trigger;
1337
+ if (trigger.type === "helm/oci") {
1338
+ return from(DockerChartImageReader.findTags({
1339
+ provider: "dockerRegistry",
1340
+ account: trigger.account,
1341
+ repository: trigger.repository
1342
+ }));
1343
+ } else {
1344
+ return from(DockerImageReader.findTags({
1345
+ provider: "dockerRegistry",
1346
+ account: trigger.account,
1347
+ repository: trigger.repository
1348
+ }));
1349
+ }
1350
+ };
1351
+ this.lookupTypeChanged = (o) => {
1352
+ const newType = o.value;
1353
+ this.updateArtifact(this.props.command, newType === "tag" ? this.state.selectedTag : this.state.digest);
1354
+ this.setState({ lookupType: newType });
1355
+ };
1356
+ this.updateSelectedTag = (tag) => {
1357
+ this.updateArtifact(this.props.command, tag);
1358
+ this.setState({ selectedTag: tag });
1359
+ this.props.command.triggerInvalid = false;
1360
+ };
1361
+ this.updateDigest = (digest) => {
1362
+ this.updateArtifact(this.props.command, digest);
1363
+ this.setState({ digest });
1364
+ };
1365
+ this.tagLoadSuccess = (tags) => {
1366
+ const { command } = this.props;
1367
+ const trigger = command.trigger;
1368
+ const newState = {};
1369
+ newState.tags = tags || [];
1370
+ const defaultSelection = newState.tags.find((t) => t === trigger.tag);
1371
+ if (defaultSelection) {
1372
+ newState.selectedTag = defaultSelection;
1373
+ this.updateSelectedTag(defaultSelection);
1374
+ }
1375
+ newState.tagsLoading = false;
1376
+ this.setState(newState);
1377
+ };
1378
+ this.tagLoadFailure = () => {
1379
+ this.setState({
1380
+ tagsLoading: false,
1381
+ loadError: true
1382
+ });
1383
+ };
1384
+ this.initialize = () => {
1385
+ const { command } = this.props;
1386
+ this.props.updateCommand("triggerInvalid", true);
1387
+ this.props.updateCommand("extraFields", {
1388
+ tag: get(command, "extraFields.tag", ""),
1389
+ artifacts: get(command, "extraFields.artifacts", "")
1390
+ });
1391
+ if (this.subscription) {
1392
+ this.subscription.unsubscribe();
1393
+ }
1394
+ if (command.trigger.type !== "docker" && command.trigger.type !== "helm/oci") {
1395
+ return;
1396
+ }
1397
+ this.subscription = this.queryStream.pipe(debounceTime(250), switchMap(this.handleQuery)).subscribe(this.tagLoadSuccess, this.tagLoadFailure);
1398
+ this.searchTags();
1399
+ };
1400
+ this.searchTags = (query = "") => {
1401
+ this.setState({ tags: [`<span>Finding tags${query && ` matching ${query}`}...</span>`] });
1402
+ this.queryStream.next();
1403
+ };
1404
+ this.state = {
1405
+ digest: "",
1406
+ tags: [],
1407
+ tagsLoading: true,
1408
+ loadError: false,
1409
+ lookupType: "tag",
1410
+ selectedTag: ""
1411
+ };
1412
+ }
1413
+ static formatLabel(trigger) {
1414
+ return $q.when(`(Docker Registry) ${trigger.account ? trigger.account + ":" : ""} ${trigger.repository || ""}`);
1415
+ }
1416
+ updateArtifact(command, tagOrDigest) {
1417
+ this.props.updateCommand("extraFields.tag", tagOrDigest);
1418
+ const trigger = command.trigger;
1419
+ if (trigger && trigger.repository) {
1420
+ let imageName = "";
1421
+ if (trigger.registry) {
1422
+ imageName += trigger.registry + "/";
1423
+ }
1424
+ imageName += trigger.repository;
1425
+ let imageReference = "";
1426
+ if (this.state.lookupType === "digest") {
1427
+ imageReference = `${imageName}@${tagOrDigest}`;
1428
+ } else {
1429
+ imageReference = `${imageName}:${tagOrDigest}`;
1430
+ }
1431
+ const artifactType = trigger.type === "docker" ? "docker/image" : "helm/image";
1432
+ this.props.updateCommand("extraFields.artifacts", [
1433
+ {
1434
+ type: artifactType,
1435
+ name: imageName,
1436
+ version: tagOrDigest,
1437
+ reference: imageReference
1438
+ }
1439
+ ]);
1440
+ }
1441
+ }
1442
+ componentDidMount() {
1443
+ this.initialize();
1444
+ }
1445
+ componentWillUnmount() {
1446
+ if (this.subscription) {
1447
+ this.subscription.unsubscribe();
1448
+ }
1449
+ }
1450
+ render() {
1451
+ const { digest, tags, tagsLoading, loadError, selectedTag, lookupType } = this.state;
1452
+ const options = tags.map((tag) => {
1453
+ return { value: tag };
1454
+ });
1455
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
1456
+ className: "form-group"
1457
+ }, /* @__PURE__ */ React.createElement("div", {
1458
+ className: "sm-label-right col-md-4"
1459
+ }, "Type"), /* @__PURE__ */ React.createElement("div", {
1460
+ className: "col-md-3"
1461
+ }, /* @__PURE__ */ React.createElement(TetheredSelect, {
1462
+ clearable: false,
1463
+ value: lookupType,
1464
+ options: lookupTypeOptions,
1465
+ onChange: this.lookupTypeChanged
1466
+ }))), lookupType === "tag" && /* @__PURE__ */ React.createElement("div", {
1467
+ className: "form-group"
1468
+ }, /* @__PURE__ */ React.createElement("label", {
1469
+ className: "col-md-4 sm-label-right"
1470
+ }, "Tag"), tagsLoading && /* @__PURE__ */ React.createElement("div", {
1471
+ className: "col-md-6"
1472
+ }, /* @__PURE__ */ React.createElement("div", {
1473
+ className: "form-control-static text-center"
1474
+ }, /* @__PURE__ */ React.createElement(Spinner, {
1475
+ size: "small"
1476
+ }))), loadError && /* @__PURE__ */ React.createElement("div", {
1477
+ className: "col-md-6"
1478
+ }, "Error loading tags!"), !tagsLoading && /* @__PURE__ */ React.createElement("div", {
1479
+ className: "col-md-6"
1480
+ }, tags.length === 0 && /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
1481
+ className: "form-control-static"
1482
+ }, "No tags found")), tags.length > 0 && /* @__PURE__ */ React.createElement(TetheredSelect, {
1483
+ options,
1484
+ optionRenderer: (o) => /* @__PURE__ */ React.createElement("span", null, o.value),
1485
+ clearable: false,
1486
+ value: selectedTag,
1487
+ valueRenderer: (o) => /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("strong", null, o.value)),
1488
+ onChange: (o) => this.updateSelectedTag(o.value),
1489
+ placeholder: "Search tags..."
1490
+ }))), lookupType === "digest" && /* @__PURE__ */ React.createElement("div", {
1491
+ className: "form-group"
1492
+ }, /* @__PURE__ */ React.createElement("label", {
1493
+ className: "col-md-4 sm-label-right"
1494
+ }, "Digest ", /* @__PURE__ */ React.createElement(HelpField, {
1495
+ id: "pipeline.config.docker.trigger.digest"
1496
+ })), /* @__PURE__ */ React.createElement("div", {
1497
+ className: "col-md-6"
1498
+ }, /* @__PURE__ */ React.createElement("input", {
1499
+ value: digest,
1500
+ onChange: (e) => this.updateDigest(e.target.value),
1501
+ className: "form-control input-sm",
1502
+ required: true
1503
+ }))));
1504
+ }
1505
+ }
1506
+
1507
+ const DockerTriggerExecutionStatus = (props) => {
1508
+ const trigger = props.trigger;
1509
+ return /* @__PURE__ */ React.createElement("li", null, trigger.repository, ":", trigger.tag);
1510
+ };
1511
+ Registry.pipeline.registerTrigger({
1512
+ label: "Docker Registry",
1513
+ description: "Executes the pipeline on an image update",
1514
+ key: "docker",
1515
+ component: DockerTriggerConfig,
1516
+ manualExecutionComponent: DockerTriggerTemplate,
1517
+ executionStatusComponent: DockerTriggerExecutionStatus,
1518
+ executionTriggerLabel: () => "Docker Registry",
1519
+ validators: [
1520
+ {
1521
+ type: "requiredField",
1522
+ fieldName: "account",
1523
+ message: "<strong>Registry</strong> is a required field for Docker Registry triggers."
1524
+ },
1525
+ {
1526
+ type: "requiredField",
1527
+ fieldName: "repository",
1528
+ message: "<strong>Image</strong> is a required field for Docker Registry triggers."
1529
+ },
1530
+ {
1531
+ type: "serviceAccountAccess",
1532
+ preventSave: true,
1533
+ message: `You do not have access to the service account configured in this pipeline's Docker Registry trigger.
1534
+ You will not be able to save your edits to this pipeline.`
1535
+ }
1536
+ ]
1537
+ });
1538
+ Registry.pipeline.registerTrigger({
1539
+ label: "Helm Docker Registry",
1540
+ description: "Executes the pipeline on an helm/image update",
1541
+ key: "helm/oci",
1542
+ component: DockerHelmOciTriggerConfig,
1543
+ manualExecutionComponent: DockerTriggerTemplate,
1544
+ executionStatusComponent: DockerTriggerExecutionStatus,
1545
+ executionTriggerLabel: () => "Helm Docker Registry",
1546
+ validators: [
1547
+ {
1548
+ type: "requiredField",
1549
+ fieldName: "account",
1550
+ message: "<strong>Registry</strong> is a required field for Docker Registry triggers."
1551
+ },
1552
+ {
1553
+ type: "requiredField",
1554
+ fieldName: "repository",
1555
+ message: "<strong>Image</strong> is a required field for Docker Registry triggers."
1556
+ },
1557
+ {
1558
+ type: "serviceAccountAccess",
1559
+ preventSave: true,
1560
+ message: `You do not have access to the service account configured in this pipeline's Docker Registry trigger.
1561
+ You will not be able to save your edits to this pipeline.`
1562
+ }
1563
+ ]
1564
+ });
1565
+
1566
+ const DOCKER_MODULE = "spinnaker.docker";
1567
+ module(DOCKER_MODULE, [DOCKER_PIPELINE_STAGES_BAKE_DOCKERBAKESTAGE]);
1568
+
1569
+ export { DOCKER_MODULE, DockerChartImageReader, DockerImageAndTagSelector, DockerImageReader, DockerImageUtils };
2
1570
  //# sourceMappingURL=index.js.map