@shoc/shoc
Version:
Run your jobs on Shoc Platform via Shoc CLI.
5 lines (4 loc) • 37.5 kB
JavaScript
var xe="1.0.2";import{createCommand as Jt}from"commander";import{promises as ce}from"fs";import*as V from"path";import*as q from"yaml";var Ht=".shoc",Gt="config.yaml",le=V.join(process.env.HOME||"",Ht,Gt);async function L(){try{let o=await ce.readFile(le,"utf8");return q.parse(o)}catch{return null}}async function $e(o){let e=V.dirname(le);await ce.mkdir(e,{recursive:!0}),await ce.writeFile(le,q.stringify(o),"utf8")}import K from"chalk";var n={error(...o){console.log(K.red(...o))},warn(...o){console.log(K.yellow(...o))},info(...o){console.log(K.cyan(...o))},success(...o){console.log(K.green(...o))},just(...o){console.log(...o)},table(...o){console.table(...o)},break(){console.log("")}};import{createCommand as Vt}from"commander";import qt from"prompts";var P="build.shoc.yaml",Re="run.shoc.yaml";function Wt(o){let e=o;for(;e.parent;)e=e.parent;return e}function w(o){let t=Wt(o).opts();return{context:t.context,workspace:t.workspace,dir:t.dir}}var f=o=>(...e)=>{o(...e).catch(t=>{n.error(`${t.message}`),process.exit(1)})};var ve=Vt("init"),Te="https://shoc.dev";ve.description("Initialize the configuration").action(f(async o=>{if(await L()){n.warn("The configuration is already initialized.");return}let t=await(await fetch(`${Te}/well-known/endpoints`)).json(),r={providers:[{name:"global",url:Te,api:t.api,identity:t.idp}],contexts:[],defaultContext:"default"},s=o.workspace;s||(s=(await qt({type:"text",name:"name",message:"Please enter your workspace name"})).name),r.contexts.push({name:"default",provider:"global",workspace:s}),await $e(r),n.info("Configuration was successfully initialized.")}));var Be=ve;import{createCommand as Kt}from"commander";var Ae=Kt("view");Ae.description("View the configuration").action(f(async()=>{let o=await L();if(!o){n.warn('No configuration found. Run "shoc config init" to create one.');return}n.just("Available providers"),(o.providers||[]).forEach(e=>{n.just(` - Name: ${e.name}, Url: ${e.url}`)}),n.break(),n.just("Available contexts"),(o.contexts||[]).forEach(e=>{let t=e.name===o.defaultContext,r=` - Name: ${e.name}, Provider: ${e.provider}, Workspace: ${e.workspace} ${t?"(default)":""}`;(t?n.success:n.just)(r)})}));var Ee=Ae;var pe=Jt("config");pe.addCommand(Be);pe.addCommand(Ee);var je=pe;import{createCommand as lo}from"commander";import Se from"fs";async function g(o){let{context:e,workspace:t,dir:r}=o,s=await L();if(!s)throw new Error('The Shoc CLI is not configured. You can run "shoc config init" to configure it.');let i=e??s.defaultContext,a=s.contexts.filter(c=>c.name===i)[0];if(!a)throw new Error(`The context '${i}' could not be resolved. Please check the configuration.`);let l=s.providers.filter(c=>c.name===a.provider)[0];if(!l)throw new Error(`The provider '${a.provider}' from the context '${a.name}' could not be resolved. Please check the configuration.`);if(!URL.canParse(l.url))throw new Error(`The provider ${l.name} has invalid URL (${l.url})`);if(!URL.canParse(l.api))throw new Error(`The provider ${l.name} has invalid API URL (${l.api})`);if(!URL.canParse(l.identity))throw new Error(`The provider ${l.name} has invalid Identity URL (${l.identity})`);let h=r??process.cwd();if(h.endsWith("/")&&(h=h.substring(0,h.length-1)),!Se.existsSync(h))throw new Error(`The directory ${h} does not exist`);if(!Se.lstatSync(h).isDirectory())throw new Error(`The path ${h} is not a directory`);return{name:a.name,providerName:l.name,providerUrl:new URL(l.url),apiUrl:new URL(l.api),identityUrl:new URL(l.identity),workspace:t??a.workspace,dir:h}}import{createCommand as no}from"commander";import Zt from"open";import Qt from"http";import me from"crypto";import Xt from"net";async function Ie(){return new Promise(o=>{let e=Xt.createServer();e.listen(0,()=>{let t=e.address().port;e.close(()=>o(t))})})}import ue from"axios";var eo=5*60,J={clientId:"cli",scope:"openid email profile shoc offline_access"};async function Le(o){let e=new URL(o);e.pathname="/.well-known/openid-configuration";try{let t=(await ue.get(e.toString())).data;return{authorizationEndpoint:t.authorization_endpoint,tokenEndpoint:t.token_endpoint}}catch(t){throw Error(`Unable to obtain configuration to start authentication. Details: ${t?.message||"Unknown Reason"}.`)}}async function Pe({idp:o,accessToken:e,refreshToken:t}){let r=await Le(o),s=new URLSearchParams({grant_type:"refresh_token",client_id:J.clientId,refresh_token:t,access_token:e}),a=(await ue.post(r.tokenEndpoint,s)).data;return{accessToken:a.access_token,refreshToken:a.refresh_token}}async function Ue({idp:o}){let e=await Ie(),t=await Le(o),r=me.randomBytes(16).toString("hex"),s=me.randomBytes(32).toString("hex"),i=me.createHash("sha256").update(s).digest("base64url"),a=`http://localhost:${e}/signed-in`,l=`${t.authorizationEndpoint}?${new URLSearchParams({response_type:"code",client_id:J.clientId,redirect_uri:a,scope:J.scope,state:r,code_challenge:i,code_challenge_method:"S256"}).toString()}`;n.info("To complete authentication please login in the browser..."),await Zt(l).catch(()=>{n.info(`If login page was not opened automatically, please use the following link to login: ${l}`)});let h=await to({port:e});if(h.state!==r)throw Error("Authentication failed due to state mismatch");if(!h.code)throw Error("Authentication failed due to missing authorization code");return await so({tokenUrl:t.tokenEndpoint,code:h.code,codeVerifier:s,redirectUri:a})}async function to({port:o}){let e=Qt.createServer();e.listen(o,()=>{n.info("Waiting for the user to complete authentication in the browser...")});let t=new AbortController;try{return await Promise.race([oo(e),ro(eo,t)])}finally{t.abort(),e.close()}}function oo(o){return new Promise(e=>{o.on("request",(t,r)=>{if(!t.url?.includes("signed-in")){r.writeHead(404),r.end("Not found");return}let s=new URL(t.url||"",`http://${t.headers.host}`).searchParams,i=s.get("code"),a=s.get("state");e({code:i,state:a}),r.writeHead(200),r.end("Authentication is in progress. You can close the browser.")})})}function ro(o,e){return new Promise((t,r)=>{let s=setTimeout(()=>{r(new Error(`Authentication was not completed within ${o/60} minutes.`)),e.abort()},o*1e3);e.signal.addEventListener("abort",()=>{clearTimeout(s)})})}async function so({tokenUrl:o,code:e,codeVerifier:t,redirectUri:r}){let s=new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:r,client_id:J.clientId,code_verifier:t}),a=(await ue.post(o.toString(),s)).data;return{accessToken:a.access_token,refreshToken:a.refresh_token}}import B from"keytar";import{decodeJwt as io}from"jose";var Q="shoc_access_token",de="shoc_refresh_token";async function fe(o,e){await B.setPassword(o,Q,e.accessToken),await B.setPassword(o,de,e.refreshToken)}async function X(o){let e=await B.getPassword(o,Q);if(!e)return null;let t=io(e),r=new Date((t.exp||0)*1e3),s=r.getTime()<new Date().getTime();return{id:t.sub||"",sub:t.sub||"",email:t.email,name:t.name,username:t.preferred_username,userType:t.user_type,expires:r,expired:s}}async function Z(o){await B.deletePassword(o,Q),await B.deletePassword(o,de)}async function U(o){let e=o.providerUrl.toString(),t=await X(e),r=await B.getPassword(e,Q),s=await B.getPassword(e,de);if(!r||!t)throw Error("You need to authenticate to continue.");if(!t.expired)return{session:t,accessToken:r,refreshToken:s};if(!s)throw Error("Your session has expired. Please login again.");let i=o.identityUrl,a=null;try{a=await Pe({idp:i,accessToken:r,refreshToken:s}),await fe(e,{accessToken:a.accessToken,refreshToken:a.refreshToken||s})}catch{await Z(e)}let l=await X(e);if(!l||!a)throw await Z(e),Error("Could not extend your session, please login again.");return{session:l,accessToken:a.accessToken,refreshToken:a.refreshToken||s}}var _e=no("login");_e.description("Authenticate the user in the provider").action(f(async(o,e)=>{let t=await g(w(e)),{accessToken:r,refreshToken:s}=await Ue({idp:t.identityUrl});fe(t.providerUrl.toString(),{accessToken:r,refreshToken:s}),n.success("You have been successfully authenticated.")}));var Fe=_e;import{createCommand as ao}from"commander";import ee from"chalk";var De=ao("session");De.description("Show details of the current session").action(f(async(o,e)=>{let t=await g(w(e)),r=await X(t.providerUrl.toString());if(!r){n.warn("You are not authenticated yet.");return}n.just(`Session details as of now (${new Date().toLocaleString()}):`),n.just(` - Status: ${r.expired?ee.yellow("Expired"):ee.green("Active")}`),n.just(` - Valid Until: ${r.expired?ee.yellow(r.expires.toLocaleString()):ee.green(r.expires.toLocaleString())}`),n.just(` - ID: ${r.id}`),n.just(` - Name: ${r.name}`),n.just(` - Email: ${r.email}`),n.just(` - Username: ${r.username}`),n.just(` - Type: ${r.userType}`)}));var Ne=De;import{createCommand as co}from"commander";var Me=co("logout");Me.description("Logout from the provider").action(f(async(o,e)=>{let t=await g(w(e));await Z(t.providerUrl.toString()),n.success("You have been logged out successfully!")}));var Oe=Me;var te=lo("auth");te.addCommand(Fe);te.addCommand(Ne);te.addCommand(Oe);var Ye=te;import{createCommand as ir}from"commander";import{createCommand as ho}from"commander";import{createCommand as fo}from"commander";function ze(o){return{root:o,gateway:"",serviceRouting:!0,client:"cli",timeout:6e4}}function u(o,e){return new e(ze(o))}import po from"axios";var N=class{service;config;constructor(e,t){this.service=e,this.config=t}authBearer(e){return{Authorization:`Bearer ${e}`}}authBasic(e,t){return{Authorization:`Basic ${Buffer.from(`${e}:${t}`).toString("base64")}`}}allowCORS(){return{"Access-Control-Allow-Origin":"*"}}contentType(e){return e?{"Content-Type":e}:{"Content-Type":"application/json"}}form(e){let t=new FormData;return Object.keys(e).forEach(r=>t.append(r,e[r])),t}esc(e){return encodeURIComponent(e)}paramValue(e){return Array.isArray(e)?e.map(this.esc).join(","):this.esc(e)}queryParams(e={}){return Object.keys(e).map(t=>this.mapQueryParam(t,e[t])).join("&")}mapQueryParam(e,t){return t==null||t===""?`${this.esc(e)}`:`${this.esc(e)}=${this.paramValue(t)}`}getApi(e){let t=this.config.root,r=this.config.gateway,s=r===""?"":"/";return this.config.serviceRouting?`${t}${r}${s}${this.service}/${e}`:`${t}${e}`}urlify(e){let t=this.getApi(e.api);return e.query&&(t=`${t}?${this.queryParams(e.query)}`),t}isError(e){return e&&e.stack&&e.message&&typeof e.stack=="string"&&typeof e.message=="string"}};var y=class extends N{webClient;constructor(e,t){super(e,t),this.webClient=po.create({timeout:t.timeout,headers:{...this.contentType(),...this.allowCORS(),client:t.client}})}isXXX(e,t){return e&&e.response&&e.response.status===t}is404(e){return this.isXXX(e,404)}is401(e){return this.isXXX(e,401)}};var k=class extends y{constructor(e){super("shoc-workspace",e)}getAll(e){let t=this.urlify({api:"api/user-workspaces"});return this.webClient.get(t,{headers:{...this.authBearer(e)}})}getById(e,t){let r=this.urlify({api:`api/user-workspaces/${t}`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}getPermissionsById(e,t){let r=this.urlify({api:`api/user-workspaces/${t}/permissions`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}getByName(e,t){let r=this.urlify({api:`api/user-workspaces/by-name/${t}`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}getPermissionsByName(e,t){let r=this.urlify({api:`api/user-workspaces/by-name/${t}/permissions`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t){let r=this.urlify({api:"api/user-workspaces"});return this.webClient.post(r,t,{headers:{...this.authBearer(e)}})}updateById(e,t,r){let s=this.urlify({api:`api/user-workspaces/${t}`});return this.webClient.put(s,r,{headers:{...this.authBearer(e)}})}deleteById(e,t){let r=this.urlify({api:`api/user-workspaces/${t}`});return this.webClient.delete(r,{headers:{...this.authBearer(e)}})}};var _=class extends Error{kind;code;payload;constructor(e,t,r,s){super(r),this.kind=e,this.code=t,this.payload=s}};var mo={UNKNOWN_ERROR:"Unknown Error",NOT_FOUND_ERROR:"The requested object could not be found"};function he(o){return mo[o]||o}import{AxiosError as uo}from"axios";async function d(o,e){let t=await U(o);try{return(await e({apiRoot:o.apiUrl.toString(),token:t.accessToken})).data}catch(r){throw He(r)}}async function oe(o,e){try{return(await e({apiRoot:o.apiUrl.toString()})).data}catch(t){throw He(t)}}function He(o){if(o instanceof _)return Error(o.message||he(o.code));if(o instanceof uo&&o.response&&o.response.headers&&o.response.headers["x-shoc-error"]==="aggregate"&&o.response?.data?.errors){let t=o.response.data.errors[0];return t?.message?Error(`${t.message} (${t.code})`):Error(he(t?.code||""))}return Error(o.message)}var Ge=fo("list");Ge.description("List my workspaces").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,s=>u(s.apiRoot,k).getAll(s.token));n.just("Available workspaces:"),n.break(),r.forEach(s=>{n.just(` - Name: ${s.name}`),n.just(` Description: ${s.description}`),n.just(` Role: ${s.role}`),n.break()})}));var We=Ge;var Ve=ho("workspaces");Ve.addCommand(We);var qe=Ve;import{createCommand as wo}from"commander";import{createCommand as go}from"commander";var A=class extends y{constructor(e){super("shoc-cluster",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-clusters`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}getByName(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-clusters/by-name/${r}`});return this.webClient.get(s,{headers:{...this.authBearer(e)}})}countAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-clusters/count`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-clusters`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}ping(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-clusters/ping`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}};var Ke=go("list");Ke.description("List my clusters").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,i=>u(i.apiRoot,k).getByName(i.token,t.workspace)),s=await d(t,i=>u(i.apiRoot,A).getAll(i.token,r.id));n.just("Available clusters:"),n.break(),s.forEach(i=>{n.just(` - Name: ${i.name}`),n.just(` Description: ${i.description||"N/A"}`),n.just(` Status: ${i.status}`),n.break()})}));var Je=Ke;var Xe=wo("clusters");Xe.addCommand(Je);var Ze=Xe;import{createCommand as ko}from"commander";import{createCommand as yo}from"commander";var M=class extends y{constructor(e){super("shoc-secret",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}countAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets/count`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}updateById(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets/${r}`});return this.webClient.put(i,s,{headers:{...this.authBearer(e)}})}updateValueById(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets/${r}/value`});return this.webClient.put(i,s,{headers:{...this.authBearer(e)}})}deleteById(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-user-secrets/${r}`});return this.webClient.delete(s,{headers:{...this.authBearer(e)}})}};var Qe=yo("list");Qe.description("List my secrets").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,i=>u(i.apiRoot,k).getByName(i.token,t.workspace)),s=await d(t,i=>u(i.apiRoot,M).getAll(i.token,r.id));n.just("List of defined user secrets:"),s.forEach(i=>{n.just(` - Name: ${i.name}, Encrypted: ${i.encrypted?"\u2713":"\u2717"}, Value: ${i.value}`)})}));var et=Qe;var tt=ko("user-secrets");tt.addCommand(et);var ot=tt;import{createCommand as bo}from"commander";import{createCommand as Co}from"commander";var O=class extends y{constructor(e){super("shoc-secret",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-secrets`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}countAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/workspace-secrets/count`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-secrets`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}updateById(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/workspace-secrets/${r}`});return this.webClient.put(i,s,{headers:{...this.authBearer(e)}})}updateValueById(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/workspace-secrets/${r}/value`});return this.webClient.put(i,s,{headers:{...this.authBearer(e)}})}deleteById(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/workspace-secrets/${r}`});return this.webClient.delete(s,{headers:{...this.authBearer(e)}})}};var rt=Co("list");rt.description("List workspace secrets").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,i=>u(i.apiRoot,k).getByName(i.token,t.workspace)),s=await d(t,i=>u(i.apiRoot,O).getAll(i.token,r.id));n.just("List of defined workspace secrets:"),s.forEach(i=>{n.just(` - Name: ${i.name}, Encrypted: ${i.encrypted?"\u2713":"\u2717"}, Value: ${i.value}`)})}));var st=rt;var it=bo("workspace-secrets");it.addCommand(st);var nt=it;import{createCommand as To}from"commander";import{createCommand as xo}from"commander";var E=class extends y{constructor(e){super("shoc-package",e)}getAll(){let e=this.urlify({api:"api/templates"});return this.webClient.get(e)}getBuildSpecInstanceByName(e,t){let r=this.urlify({api:`api/templates/${e}/variants/${t}/build-spec/instance`});return this.webClient.get(r)}};var at=xo("list");at.description("List available templates").action(f(async(o,e)=>{let t=await g(w(e)),r=await oe(t,s=>u(s.apiRoot,E).getAll());n.just("Available templates:"),r.forEach(s=>{n.just(` - ${s.name}:[${s.variants.join(", ")}]`)})}));var ct=at;import{createCommand as $o}from"commander";import lt from"fs";import{stringify as Ro}from"yaml";var pt=$o("init");pt.description("Initialize the target folder with the selected template").argument("<template>","The template name and variant to initialize. Example: alpine:default.").action(f(async(o,e,t)=>{let r=await g(w(t)),s=o.split(":",2),i=s[0].trim(),a=(s[1]||"default").trim(),l=await oe(r,v=>u(v.apiRoot,E).getBuildSpecInstanceByName(i,a));n.info(`Initializing the template in the current directory (${r.dir})...`);let h={template:`${i}:${a}`,spec:l,ignore:[]},c=`${r.dir}/${P}`;if(lt.existsSync(c))throw Error(`The build file ${P} already exists!`);let T=Ro(h);lt.writeFileSync(c,T),n.success(`Initialized the build file (${P}) with the template ${i}:${a}`)}));var mt=pt;var ge=To("templates");ge.addCommand(ct);ge.addCommand(mt);var ut=ge;import{createCommand as Io}from"commander";var $=class extends y{constructor(e){super("shoc-job",e)}getBy(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/jobs`,query:{...r}});return this.webClient.get(s,{headers:{...this.authBearer(e)}})}getByLocalId(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/jobs/by-local-id/${r}`});return this.webClient.get(s,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/jobs`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}submit(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/jobs/${r}/submit`});return this.webClient.post(i,s,{headers:{...this.authBearer(e)}})}};import{table as Lo}from"table";import dt from"dayjs";import vo from"dayjs/plugin/utc.js";dt.extend(vo);var Y=dt;var re=o=>o?Y.utc(o).local().format("YYYY-MM-DD HH:mm:ss"):"";var Bo=()=>Y.utc().toDate();function F(o,e){let t=Y.utc(o).toDate(),r=e?Y.utc(e).toDate():Bo(),s=Math.floor((r.getTime()-t.getTime())/1e3),i=s<0?"-":"";s=Math.abs(s);let a=Math.floor(s/86400),l=Math.floor(s%86400/3600),h=Math.floor(s%3600/60),c=s%60,T=`${String(l).padStart(2,"0")}:${String(h).padStart(2,"0")}:${String(c).padStart(2,"0")}`;return a>0?`${i}${a}.${T}`:`${i}${T}`}import{createCommand as Ao}from"commander";import{table as Eo}from"table";import ft from"chalk";var ht=Ao("details");ht.description("Show details of the job").requiredOption("-j, --job <number>","The job number").option("--json","The raw json object").action(f(async(o,e)=>{let t=parseInt(o.job,10);if(!Number.isSafeInteger(t))throw Error(`The ${o.job} is not valid key for job`);let r=await g(w(e)),s=await d(r,l=>u(l.apiRoot,k).getByName(l.token,r.workspace)),i=await d(r,l=>u(l.apiRoot,$).getByLocalId(l.token,s.id,t));if(o.json){n.just(JSON.stringify(i,null,4));return}let a=[[ft.bold("Name"),ft.bold("Value")],["Id",i.id],["Job Key",i.localId],["Workspace",i.workspaceName],["Cluster",i.clusterName],["User",i.userFullName],["Scope",i.scope],["Namespace",i.namespace],["Status",i.status],["Tasks",i.totalTasks],["Completed Tasks",i.completedTasks],["Succeeded Tasks",i.succeededTasks],["Failed Tasks",i.failedTasks],["Cancelled Tasks",i.cancelledTasks],["Pending Since",re(i.pendingAt)],["Running Since",re(i.runningAt)],["Completed At",re(i.completedAt)]];n.just(Eo(a,{drawHorizontalLine:()=>!1,drawVerticalLine:()=>!1}))}));var gt=ht;import{createCommand as jo}from"commander";import{table as So}from"table";var j=class extends y{constructor(e){super("shoc-job",e)}getAll(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/jobs/${r}/tasks`});return this.webClient.get(s,{headers:{...this.authBearer(e)}})}getLogsBySequenceUrl(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/jobs/${r}/tasks/by-sequence/${s}/logs`});return Promise.resolve({data:{token:e,url:i}})}};var wt=jo("tasks");wt.description("Show tasks of the job").requiredOption("-j, --job <number>","The job number").option("--json","The raw json object").action(f(async(o,e)=>{let t=parseInt(o.job,10);if(!Number.isSafeInteger(t))throw Error(`The ${o.job} is not valid key for job`);let r=await g(w(e)),s=await d(r,c=>u(c.apiRoot,k).getByName(c.token,r.workspace)),i=await d(r,c=>u(c.apiRoot,$).getByLocalId(c.token,s.id,t)),a=await d(r,c=>u(c.apiRoot,j).getAll(c.token,s.id,i.id));if(o.json){n.just(JSON.stringify(a,null,4));return}let h=[["Sequence","Status","Cluster","User","Type","Waiting","Running"]];a.forEach(c=>h.push([c.sequence??"",c.status??"",c.clusterName??"",c.userFullName??"",c.type??"",F(c.created,c.runningAt),c.runningAt?F(c.runningAt,c.completedAt):"N/A"])),n.just(So(h,{drawHorizontalLine:()=>!1,drawVerticalLine:()=>!1}))}));var yt=wt;import Po from"chalk";var se=Io("jobs").aliases(["job"]);se.addCommand(gt);se.addCommand(yt);se.description("List available jobs").option("--page <number>","The page number","0").option("--size <number>","The size of the result","10").option("--status <string>","The status to filter","").option("--scope <string>","The scope to filter","").option("--all","Consider all jobs in the workspace","true").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,C=>u(C.apiRoot,k).getByName(C.token,t.workspace)),s=o.page??0,i=o.size??20,a=o.all,l=o.status,h=o.scope,c={status:l,scope:h,all:a,page:s,size:i},{items:T,totalCount:v}=await d(t,C=>u(C.apiRoot,$).getBy(C.token,r.id,c)),m=[["Job","Name","Status","Cluster","User","Completed","Scope","Waiting","Running"]];T.forEach(C=>m.push([C.localId??"",C.name?C.name:Po.italic("No name"),C.status??"",C.clusterName??"",C.userFullName??"",`${C.completedTasks} / ${C.totalTasks}`,C.scope,F(C.created,C.runningAt),C.runningAt?F(C.runningAt,C.completedAt):"N/A"])),n.just(Lo(m,{drawHorizontalLine:()=>!1,drawVerticalLine:()=>!1})),n.just(`Current page ${s}: ${T.length} jobs out of ${v}`)}));var kt=se;import{createCommand as Go}from"commander";import ie from"fs";import we from"path";import*as Ct from"yaml";import{promises as ye}from"fs";import{glob as Uo}from"glob";import bt from"crypto";import _o from"os";import Fo from"archiver";var Do=["**/.git/**","**/node_modules/**","**/run.shoc.yaml","**/run.shoc.yml"],No="shoc-temp",Mo=16;async function Oo(o){let e=we.resolve(o.dir,o.buildFile||P);if(!ie.existsSync(e))throw Error(`The build file ${e} could not be found!`);let t=await ye.stat(e);return{fullPath:e,modified:t.mtime.getTime(),size:t.size}}async function xt(o){let e=await Oo(o),t=await ye.readFile(e.fullPath,"utf8");return{manifest:Ct.parse(t),buildFile:e}}async function $t(o,e){let t=await Uo("**/*",{ignore:[...Do,...e.ignore||[]],cwd:o.dir,nodir:!0,withFileTypes:!0}),r=[];for(let s of t){let i=await ye.stat(s.fullpath());r.push({fullPath:s.fullpath(),localPath:s.relative(),modified:i.mtime.getTime(),size:i.size})}return r.sort((s,i)=>s.localPath.localeCompare(i.localPath)),{files:r}}function Rt(o,e){let t=[];return t.push(`__BUILD_FILE__:${o.size}:${o.modified}`),e.forEach(r=>t.push(`${r.localPath}:${r.size}:${r.modified}`)),bt.createHash("sha256").update(t.join(",")).digest("hex")}function Yo(){let o=we.join(_o.tmpdir(),No);return ie.existsSync(o)||ie.mkdirSync(o,{recursive:!0}),o}async function Tt(o){return new Promise((e,t)=>{let r=`${bt.randomBytes(Mo).toString("hex")}.zip`,s=we.join(Yo(),r),i=ie.createWriteStream(s),a=Fo("zip",{zlib:{level:9}});i.on("close",()=>{e(s)}),a.on("error",l=>{t(l)}),a.pipe(i),o.forEach(l=>{a.file(l.fullPath,{name:l.localPath})}),a.finalize()})}var D=class extends y{constructor(e){super("shoc-package",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/build-tasks`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/build-tasks`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}uploadBundleById(e,t,r,s){let i=this.urlify({api:`api/workspaces/${t}/build-tasks/${r}/bundle`});return this.webClient.put(i,s,{headers:{...this.authBearer(e),"Content-Type":"multipart/form-data"},timeout:2*60*60*1e3,maxBodyLength:1/0})}};import{fileFromPath as zo}from"formdata-node/file-from-path";import x from"chalk";var z=class extends y{constructor(e){super("shoc-package",e)}fromCache(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/packages/from-cache`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)},timeout:2*60*60*1e3})}};import ne,{oraPromise as S}from"ora";async function H(o,e){e.authenticatedContext??await S(U(o),{text:"Validating user authentication",successText:m=>`\u{1F511} Authenticated by ${x.bold(m.session.name)} at ${x.bold(e.workspace)}`,failText:m=>`Could not authenticate: ${x.red(m.message)}`}).catch(()=>process.exit(1)),ne().succeed(`\u{1F4C1} Using ${x.bold(e.dir)} as a package directory`),ne().succeed(`\u{1F441}\uFE0F Packaing with scope ${x.bold(e.scope)}`);let{buildFile:t,manifest:r}=await S(xt(e),{successText:m=>`\u{1F4C4} Detected build manifest at ${x.bold(m.buildFile.fullPath)}`,failText:m=>`Build manifest could not be found: ${x.red(m.message)}`}).catch(()=>process.exit(1)),{files:s}=await S($t(e,r),{successText:m=>`\u{1F5C3}\uFE0F Detected ${x.bold(m.files.length)} files to package`,failText:m=>`Could not fetch the list of files to package: ${x.red(m.message)}`}).catch(()=>process.exit(1)),i=Rt(t,s);ne().succeed(`\u{1F522} Computed checksum of the package ${x.bold(i)}`);let{id:a}=e.workspaceReference??await S(d(o,m=>u(m.apiRoot,k).getByName(m.token,e.workspace)),{text:`Validating workspace ${x.bold(e.workspace)}`,successText:m=>`\u{1F30E} Workspace ${x.bold(m.name)} is valid`,failText:m=>`The workspace ${x.bold(e.workspace)} is not valid: ${x.red(m.message)}`}).catch(()=>process.exit(1)),l=await S(Ho(o,{workspaceId:a,scope:e.scope,listingChecksum:i}),{text:"Checking if the package could be restored from cache",successText:m=>m?"\u{1F4E6} The package has been already built":"\u2139\uFE0F The package was not cached",failText:m=>`Could not perform the cache check: ${x.red(m.message)}`}).catch(()=>process.exit(1));if(l)return{packageId:l.packageId};let h={workspaceId:a,provider:"remote",scope:e.scope,listingChecksum:i,manifest:JSON.stringify(r)},c=await S(d(o,m=>u(m.apiRoot,D).create(m.token,a,h)),{text:"Starting a build process for the package",successText:m=>`\u{1F528} Build process is successfully initiated with reference ${x.bold(m.id)}`,failText:m=>`Could not initiate the build process: ${x.red(m.message)}`}),T=await Tt(s),v=new FormData;v.append("file",await zo(T));let p=await S(d(o,m=>u(m.apiRoot,D).uploadBundleById(m.token,a,c.id,v)),{text:"Uploading the package bundle to build",successText:m=>`\u{1F4E6} The package was successfully built with reference ${x.bold(m.packageId)}`,failText:m=>`Could not upload and build the package: ${x.red(m.message)}`});return p.status==="failed"&&(ne().fail(`The package build failed: ${p.message} (${p.errorCode})`),process.exit(1)),{packageId:p.packageId}}async function Ho(o,e){try{return{packageId:(await d(o,r=>u(r.apiRoot,z).fromCache(r.token,e.workspaceId,e))).id}}catch(t){if(t instanceof _&&t.kind==="not_found")return null}return null}var vt=Go("build");vt.description("Build a package from the selected directory").option("-f, --build-file <buildFile>","The name of the build file to use").option("--scope <scope>","The scope of the build (user or workspace)","workspace").action(f(async(o,e)=>{let t=await g(w(e)),r=Wo(t,o),s=await H(t,r)}));function Wo(o,e){return{workspace:o.workspace,dir:o.dir,buildFile:e.buildFile,scope:e.scope}}var Bt=vt;import{createCommand as tr}from"commander";import b from"chalk";import{oraPromise as I}from"ora";var G=class extends y{constructor(e){super("shoc-job",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/git-repos`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/git-repos`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}ensure(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/git-repos/ensure`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}};import ke from"isomorphic-git";import Ce from"fs";import Vo from"git-url-parse";async function At(o){try{return await qo(o)}catch{return null}}async function qo(o){let e=await ke.findRoot({fs:Ce,filepath:o}),t=await ke.listRemotes({fs:Ce,dir:e});if(t.length===0)return null;let r=t.filter(a=>a.remote==="origin")[0];r||(r=t[0]);let s=await ke.currentBranch({fs:Ce,dir:e,fullname:!1}),i=Vo(r.url);return{remote:r.remote,url:r.url,branch:s,source:i.source,owner:i.owner,name:i.name,repo:i.full_name}}import Ko from"fs";import*as Et from"yaml";import{promises as Jo}from"fs";import Xo from"path";var W=class extends y{constructor(e){super("shoc-job",e)}getAll(e,t){let r=this.urlify({api:`api/workspaces/${t}/labels`});return this.webClient.get(r,{headers:{...this.authBearer(e)}})}create(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/labels`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}ensure(e,t,r){let s=this.urlify({api:`api/workspaces/${t}/labels/ensure`});return this.webClient.post(s,r,{headers:{...this.authBearer(e)}})}};async function jt(o){let e=Xo.resolve(o.dir,o.runFile||Re);if(!Ko.existsSync(e))throw Error(`The run file ${e} could not be found!`);let t=await Jo.readFile(e,"utf8");return{manifest:Et.parse(t),runFile:e}}async function St(o,e,t,r){let s=await At(e.dir),i=s?await Zo(o,t,s):null,a=!r.labels||r.labels.length===0?[]:await Qo(o,t,r.labels);return{gitRepoId:i,labelIds:a}}async function Zo(o,e,t){let r={workspaceId:e,name:t.name,owner:t.owner,source:t.source,repository:t.repo,remoteUrl:t.url};try{return(await d(o,i=>u(i.apiRoot,G).ensure(i.token,e,r))).id}catch{return null}}async function Qo(o,e,t){let r={workspaceId:e,names:t};try{return(await d(o,i=>u(i.apiRoot,W).ensure(i.token,e,r))).map(i=>i.id)}catch(s){throw Error(`Could not resolve labels ([${t.join(", ")}]): ${s?.message||"Unknown error"}`)}}function It(o){return o??[]}function Lt(o){return{replicas:o?.replicas??null,indexer:o?.indexer??null,counter:o?.counter??null}}function Pt(o){return{use:o?.use??[],override:o?.override??{}}}function Ut(o){return{cpu:ae(o?.cpu??null),memory:ae(o?.memory??null),nvidiaGpu:ae(o?.nvidiaGpu??null),amdGpu:ae(o?.amdGpu??null)}}function er(o){return{...o??{}}}function _t(o){let e={};return o?.mpi&&(e={...e,mpi:er(o.mpi)}),e}function ae(o){return o==null||typeof o>"u"?null:typeof o=="bigint"||typeof o=="number"||typeof o=="boolean"?String(o):typeof o=="string"||typeof o=="symbol"?o:null}async function be(o,e){let t=await I(U(o),{text:"Validating user authentication",successText:p=>`\u{1F511} Authenticated by ${b.bold(p.session.name)} at ${b.bold(e.workspace)}`,failText:p=>`Could not authenticate: ${b.red(p.message)}`}).catch(()=>process.exit(1)),{id:r}=await I(d(o,p=>u(p.apiRoot,k).getByName(p.token,e.workspace)),{text:`Validating workspace ${b.bold(e.workspace)}`,successText:p=>`\u{1F30E} Workspace ${b.bold(p.name)} is valid`,failText:p=>`The workspace ${b.bold(e.workspace)} is not valid: ${b.red(p.message)}`}).catch(()=>process.exit(1)),{manifest:s}=await I(jt(e),{successText:p=>`\u{1F4C4} Detected build manifest at ${b.bold(p.runFile)}`,failText:p=>`Build manifest could not be found: ${b.red(p.message)}`}).catch(()=>process.exit(1)),{gitRepoId:i,labelIds:a}=await I(St(o,e,r,s),{successText:p=>"\u2139\uFE0F Initialization completed successfully",failText:p=>`Initialization failed: ${b.red(p.message)}`}).catch(()=>process.exit(1)),{packageId:l}=await H(o,{workspace:e.workspace,dir:e.dir,buildFile:e.buildFile,scope:e.scope,workspaceReference:{id:r},authenticatedContext:t}),{id:h}=await I(d(o,p=>u(p.apiRoot,A).getByName(p.token,r,s.cluster)),{text:`Ensuring cluster ${b.bold(s.cluster)} exists`,successText:p=>`\u{1F50C} Cluster ${b.bold(p.name)} exists`,failText:p=>`The cluster ${b.bold(s.cluster)} could not be found: ${b.red(p.message)}`}).catch(()=>process.exit(1)),c={workspaceId:r,scope:e.scope,manifest:{name:s.name??"",description:s.description??"",gitRepoId:i,labelIds:a??[],clusterId:h,packageId:l,args:It(s.args),array:Lt(s.array),env:Pt(s.env),resources:Ut(s.resources),spec:_t(s.spec)}},T=await I(d(o,p=>u(p.apiRoot,$).create(p.token,r,c)),{text:"Initializing a new job in the system",successText:p=>`\u231B Job (${b.bold(p.localId)}) in workspace ${b.bold(e.workspace)} was successfully created`,failText:p=>`Could not initialize a job with the given manifest: ${b.red(p.message)}`}),v=await I(async()=>{let p=await d(o,m=>u(m.apiRoot,$).submit(m.token,r,T.id,c));if(p.status==="failed")throw Error(`Reason: ${p.message||"unknown"}`);return p},{text:"Submitting job to the cluster",successText:p=>`\u2705\uFE0F Job ${b.bold(p.localId)} is submitted to the cluster ${b.bold(s.cluster)}`,failText:p=>`Could not submit the job to the cluster: ${b.red(p.message)}`});return{}}var Ft=tr("run");Ft.description("Submit a new job according to run manifest").option("--build-file <buildFile>","The name of the build manifest file to use").option("--run-file <runFile>","The name of the run manifest file to use").option("--scope <scope>","The scope of the build (user or workspace)","workspace").action(f(async(o,e)=>{let t=await g(w(e)),r=or(t,o),s=await be(t,r)}));function or(o,e){return{workspace:o.workspace,dir:o.dir,buildFile:e.buildFile,scope:e.scope,runFile:e.runFile}}var Dt=Ft;import{createCommand as rr}from"commander";var Nt=rr("logs");Nt.description("Watch logs of the job tasks").requiredOption("-j, --job <number>","The job number").option("-t, --task <number>","The task number","0").action(f(async(o,e)=>{let t=await g(w(e)),r=await d(t,c=>u(c.apiRoot,k).getByName(c.token,t.workspace)),s=parseInt(o.job,10),i=o.task??0;if(!Number.isSafeInteger(s))throw Error(`The ${o.job} is not valid key for job`);let a=await d(t,c=>u(c.apiRoot,$).getByLocalId(c.token,r.id,s)),{url:l,token:h}=await d(t,c=>u(c.apiRoot,j).getLogsBySequenceUrl(c.token,r.id,a.id,i));try{await sr(l,h)}catch(c){n.error(`Unable to read logs: ${c.message}`)}}));async function sr(o,e){let t=await fetch(o,{headers:{"x-shoc-sse":"yes",Authorization:`Bearer ${e}`}});if(!t.ok){if(t.status===404)throw Error("The object is was not found");if(t.status===403)throw Error("No enough permissions for the operation");let{errors:i}=await t.json()??{errors:[]};throw Error(i.length>0?`${i[0].code} ${i[0]?.message}`:"Unknown error")}if(!t.body)return;let r=t.body.getReader(),s=new TextDecoder;for(;;){let{done:i,value:a}=await r.read();if(i)break;let h=s.decode(a,{stream:!0}).split(`
`);for(let c of h)c.startsWith("data: ")&&n.just(c.slice(6))}}var Mt=Nt;var R=ir();R.name("shoc").description("A command-line interface for managing your job on Shoc Platform").version(xe,"-v, --version").option("-c, --context <context>","Use the mentioned context").option("-w, --workspace <workspace>","Use the mentioned workspace").option("-d, --dir <dir>","Use the given working directory").enablePositionalOptions();R.addCommand(Bt);R.addCommand(Dt);R.addCommand(je);R.addCommand(Ye);R.addCommand(kt);R.addCommand(Mt);R.addCommand(ut);R.addCommand(qe);R.addCommand(Ze);R.addCommand(ot);R.addCommand(nt);var Ot=R;import nr from"axios";import ar from"@dotenvx/dotenvx";import cr from"https";import{Agent as lr,setGlobalDispatcher as pr}from"undici";var mr=!0;function Yt(){if(ar.config({convention:"nextjs",quiet:!0}),process.env.ALLOW_INSECURE==="yes"||mr){let o=new cr.Agent({rejectUnauthorized:!1});nr.defaults.httpsAgent=o;let e=new lr({connect:{rejectUnauthorized:!1}});pr(e)}}Yt();try{Ot.parse(process.argv)}catch(o){n.error(o.message||"Command failed due to an unexpected error"),process.exit(1)}
//# sourceMappingURL=index.js.map