Coverage for src/fastapi_cloud_cli/commands/deploy/cloud.py: 100%
51 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
1from pydantic import BaseModel 1abcdefg
3from fastapi_cloud_cli.api import ( 1abcdefg
4 APIClient,
5 DeploymentStatus,
6 _get_response_error_message,
7)
10class ArchiveTooLargeError(Exception): 1abcdefg
11 pass 1abcdefg
14class Team(BaseModel): 1abcdefg
15 id: str 1abcdefg
16 slug: str 1abcdefg
17 name: str 1abcdefg
20class AppResponse(BaseModel): 1abcdefg
21 id: str 1abcdefg
22 slug: str 1abcdefg
23 directory: str | None 1abcdefg
24 github_repository: str | None = None 1abcdefg
27class CreateDeploymentResponse(BaseModel): 1abcdefg
28 id: str 1abcdefg
29 app_id: str 1abcdefg
30 slug: str 1abcdefg
31 status: DeploymentStatus 1abcdefg
32 dashboard_url: str 1abcdefg
33 url: str 1abcdefg
36def _get_teams(client: APIClient) -> list[Team]: 1abcdefg
37 response = client.get("/teams/") 2iev jegdhdw x o y idke,e*d-ejdleme.eh kdldmdnez oendodA B p C pdpe/e+d:eqdqere;ei rdsdtdseD teudvdE F q G wdue=e,d?exdvewe@ej ydzdAdxeH yeBdCdI J r K Ddze[e-d]eEdAeBe^ek FdGdHdCeL DeIdJdM N s O KdEe_e.d`eLdFeGe{el MdNdOdHeP IePdQdQ R t S RdJe|e/d}eSdKeLe~em TdUdVdMeT NeWdXdU V u W YdOeaf:dbfZdPeQecfn 0d1d2d
38 response.raise_for_status() 2iev jegdhdw x o y idke,e*d-ejdleme.eh kdldmdnez oendodA B p C pdpe/e+d:eqdqere;ei rdsdtdseD teudvdE F q G wdue=e,d?exdvewe@ej ydzdAdxeH yeBdCdI J r K Ddze[e-d]eEdAeBe^ek FdGdHdCeL DeIdJdM N s O KdEe_e.d`eLdFeGe{el MdNdOdHeP IePdQdQ R t S RdJe|e/d}eSdKeLe~em TdUdVdMeT NeWdXdU V u W YdOeaf:dbfZdPeQecfn 0d1d2d
40 data = response.json()["data"] 2iev jegdhdw x o y idke*djdlemeh kdldmdnez oendodA B p C pdpe+dqdqerei rdsdtdseD teudvdE F q G wdue,dxdvewej ydzdAdxeH yeBdCdI J r K Ddze-dEdAeBek FdGdHdCeL DeIdJdM N s O KdEe.dLdFeGel MdNdOdHeP IePdQdQ R t S RdJe/dSdKeLem TdUdVdMeT NeWdXdU V u W YdOe:dZdPeQen 0d1d2d
42 return [Team.model_validate(team) for team in data] 2iev jegdhdw x o y idke*djdlemeh kdldmdnez oendodA B p C pdpe+dqdqerei rdsdtdseD teudvdE F q G wdue,dxdvewej ydzdAdxeH yeBdCdI J r K Ddze-dEdAeBek FdGdHdCeL DeIdJdM N s O KdEe.dLdFeGel MdNdOdHeP IePdQdQ R t S RdJe/dSdKeLem TdUdVdMeT NeWdXdU V u W YdOe:dZdPeQen 0d1d2d
45def _update_app(client: APIClient, app_id: str, directory: str | None) -> AppResponse: 1abcdefg
46 response = client.patch( 1hijklmn
47 f"/apps/{app_id}",
48 json={"directory": directory},
49 )
51 response.raise_for_status() 1hijklmn
53 return AppResponse.model_validate(response.json()) 1hijklmn
56def _create_app( 1abcdefg
57 client: APIClient, team_id: str, app_name: str, directory: str | None
58) -> AppResponse:
59 response = client.post( 2v gdhdw x y *dz ndodA B C +dD udvdE F G ,dH BdCdI J K -dL IdJdM N O .dP PdQdQ R S /dT WdXdU V W :d
60 "/apps/",
61 json={"name": app_name, "team_id": team_id, "directory": directory},
62 )
64 response.raise_for_status() 2v gdhdw x y *dz ndodA B C +dD udvdE F G ,dH BdCdI J K -dL IdJdM N O .dP PdQdQ R S /dT WdXdU V W :d
66 return AppResponse.model_validate(response.json()) 2v gdhdw x y z ndodA B C D udvdE F G H BdCdI J K L IdJdM N O P PdQdQ R S T WdXdU V W
69def _create_deployment( 1abcdefg
70 client: APIClient, app_id: str, archive_size_bytes: int
71) -> CreateDeploymentResponse:
72 response = client.post( 2X v Y w Z 0 1 2 3 3d4 5 4d6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | } 5d~ ab6dbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDbEb7dFbGb8dHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b!b9d#b$b!d%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcecfc#dgchc$dicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKcLc%dMcNc'dOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)c*c(d+c,c)d-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
73 f"/apps/{app_id}/deployments/",
74 json={"archive_size_bytes": archive_size_bytes},
75 )
77 if response.status_code == 413: 2X v Y w Z 0 1 2 3 3d4 5 4d6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | } 5d~ ab6dbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDbEb7dFbGb8dHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b!b9d#b$b!d%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcecfc#dgchc$dicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKcLc%dMcNc'dOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)c*c(d+c,c)d-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
78 raise ArchiveTooLargeError( 23d4d5d6d7d8d9d!d#d$d%d'd(d)d
79 _get_response_error_message(response)
80 or "The app source code exceeds the maximum allowed size."
81 )
83 response.raise_for_status() 2X v Y w Z 0 1 2 3 4 5 6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | } ~ abbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDbEbFbGbHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b!b#b$b%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcecfcgchcicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKcLcMcNcOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)c*c+c,c-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
85 return CreateDeploymentResponse.model_validate(response.json()) 2X v Y w Z 0 1 2 3 4 5 6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | } ~ abbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDbEbFbGbHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b!b#b$b%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcecfcgchcicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKcLcMcNcOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)c*c+c,c-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
88def _get_app(client: APIClient, app_id: str) -> AppResponse | None: 1abcdefg
89 response = client.get(f"/apps/{app_id}") 2X v Y gdhdw Z 0 1 2 ;d=d3 3d4 Re?d5 4d6 7 8 Se9 ! # Tex o y $ % ' ( ) * + , - . / : ; Ue= h ? @ [ ] z ^ ndodA _ ` { | @d[d} 5d~ Ve]dab6dbbcbdbWeebfbgbXeB p C hbibjbkblbmbnbobpbqbrbsbtbYeubi vbwbxbybD zbudvdE AbBbCbDb^d_dEb7dFbZe`dGb8dHbIbJb0eKbLbMb1eF q G NbObPbQbRbSbTbUbVbWbXbYbZb2e0bj 1b2b3b4bH 5bBdCdI 6b7b8b9b{d|d!b9d#b3e}d$b!d%b'b(b4e)b*b+b5eJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b6e`bk {b|b}b~bL acIdJdM bcccdcec~daefc#dgc7ebehc$dicjckc8elcmcnc9eN s O ocpcqcrcsctcucvcwcxcyczcAc!eBcl CcDcEcFcP GcPdQdQ HcIcJcKccedeLc%dMc#eeeNc'dOcPcQc$eRcScTc%eR t S UcVcWcXcYcZc0c1c2c3c4c5c6c'e7cm 8c9c!c#cT $cWdXdU %c'c(c)cfege*c(d+c(ehe,c)d-c.c/c)e:c;c=c*eV u W ?c@c[c]c^c_c`c{c|c}c~cadbd+ecdn ddedfd
91 if response.status_code == 404: 2X v Y w Z 0 1 2 ;d=d3 3d4 Re?d5 4d6 7 8 Se9 ! # Tex o y $ % ' ( ) * + , - . / : ; Ue= h ? @ [ ] z ^ A _ ` { | @d[d} 5d~ Ve]dab6dbbcbdbWeebfbgbXeB p C hbibjbkblbmbnbobpbqbrbsbtbYeubi vbwbxbybD zbE AbBbCbDb^d_dEb7dFbZe`dGb8dHbIbJb0eKbLbMb1eF q G NbObPbQbRbSbTbUbVbWbXbYbZb2e0bj 1b2b3b4bH 5bI 6b7b8b9b{d|d!b9d#b3e}d$b!d%b'b(b4e)b*b+b5eJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b6e`bk {b|b}b~bL acM bcccdcec~daefc#dgc7ebehc$dicjckc8elcmcnc9eN s O ocpcqcrcsctcucvcwcxcyczcAc!eBcl CcDcEcFcP GcQ HcIcJcKccedeLc%dMc#eeeNc'dOcPcQc$eRcScTc%eR t S UcVcWcXcYcZc0c1c2c3c4c5c6c'e7cm 8c9c!c#cT $cU %c'c(c)cfege*c(d+c(ehe,c)d-c.c/c)e:c;c=c*eV u W ?c@c[c]c^c_c`c{c|c}c~cadbd+ecdn ddedfd
92 return None 2ReSeUeVeWeYeZe0e2e3e4e6e7e8e!e#e$e'e(e)e+e
94 response.raise_for_status() 2X v Y w Z 0 1 2 ;d=d3 3d4 ?d5 4d6 7 8 9 ! # Tex o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | @d[d} 5d~ ]dab6dbbcbdbebfbgbXeB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDb^d_dEb7dFb`dGb8dHbIbJbKbLbMb1eF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b{d|d!b9d#b}d$b!d%b'b(b)b*b+b5eJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcec~daefc#dgcbehc$dicjckclcmcnc9eN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKccedeLc%dMceeNc'dOcPcQcRcScTc%eR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)cfege*c(d+che,c)d-c.c/c:c;c=c*eV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
96 data = response.json() 2X v Y w Z 0 1 2 ;d=d3 3d4 ?d5 4d6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | @d[d} 5d~ ]dab6dbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDb^d_dEb7dFb`dGb8dHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b{d|d!b9d#b}d$b!d%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcec~daefc#dgcbehc$dicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKccedeLc%dMceeNc'dOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)cfege*c(d+che,c)d-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
98 return AppResponse.model_validate(data) 2X v Y w Z 0 1 2 ;d=d3 3d4 ?d5 4d6 7 8 9 ! # x o y $ % ' ( ) * + , - . / : ; = h ? @ [ ] z ^ A _ ` { | @d[d} 5d~ ]dab6dbbcbdbebfbgbB p C hbibjbkblbmbnbobpbqbrbsbtbubi vbwbxbybD zbE AbBbCbDb^d_dEb7dFb`dGb8dHbIbJbKbLbMbF q G NbObPbQbRbSbTbUbVbWbXbYbZb0bj 1b2b3b4bH 5bI 6b7b8b9b{d|d!b9d#b}d$b!d%b'b(b)b*b+bJ r K ,b-b.b/b:b;b=b?b@b[b]b^b_b`bk {b|b}b~bL acM bcccdcec~daefc#dgcbehc$dicjckclcmcncN s O ocpcqcrcsctcucvcwcxcyczcAcBcl CcDcEcFcP GcQ HcIcJcKccedeLc%dMceeNc'dOcPcQcRcScTcR t S UcVcWcXcYcZc0c1c2c3c4c5c6c7cm 8c9c!c#cT $cU %c'c(c)cfege*c(d+che,c)d-c.c/c:c;c=cV u W ?c@c[c]c^c_c`c{c|c}c~cadbdcdn ddedfd
101def _get_apps(client: APIClient, team_id: str) -> list[AppResponse]: 1abcdefg
102 response = client.get("/apps/", params={"team_id": team_id}) 2o idjdh kdldmdp pdqdi rdsdtdq wdxdj ydzdAdr DdEdk FdGdHds KdLdl MdNdOdt RdSdm TdUdVdu YdZdn 0d1d2d
103 response.raise_for_status() 2o idjdh kdldmdp pdqdi rdsdtdq wdxdj ydzdAdr DdEdk FdGdHds KdLdl MdNdOdt RdSdm TdUdVdu YdZdn 0d1d2d
105 data = response.json()["data"] 2o idjdh kdldmdp pdqdi rdsdtdq wdxdj ydzdAdr DdEdk FdGdHds KdLdl MdNdOdt RdSdm TdUdVdu YdZdn 0d1d2d
107 return [AppResponse.model_validate(app) for app in data] 2o idjdh kdldmdp pdqdi rdsdtdq wdxdj ydzdAdr DdEdk FdGdHds KdLdl MdNdOdt RdSdm TdUdVdu YdZdn 0d1d2d