carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1{{define "app_releases"}}{{template "top" .}}
2{{if .Flash}}<p class="banner">{{.Flash}}</p>{{end}}
3{{if .FlashErr}}<p class="banner error">{{.FlashErr}}</p>{{end}}
4{{template "appnav" .}}
5<nav class="tabs" aria-label="{{.DeploymentsCopy.Title}}">
6 <a href="{{.Nav}}/apps/{{.AppName}}/deployments">{{.DeploymentsCopy.Title}}</a>
7 <a href="{{.Nav}}/apps/{{.AppName}}/releases" aria-current="page">{{.DeploymentsCopy.History}}</a>
8</nav>
9<h2>{{.DeploymentsCopy.History}}</h2>
10{{template "accountreviewbanner" .}}
11
12{{with .ReleaseSummary}}
13<section class="pagehead" aria-label="Release status">
14 <h2>{{$.StatusCopy.ObservedLabel}}</h2>
15 {{if not .Deployment.HasRoutes}}
16 <p>{{$.StatusCopy.NoInstances}}</p>
17 {{else if not .Deployment.HasReportable}}
18 <p>—</p>
19 {{else if not .Deployment.HasReportedVersion}}
20 <p>{{$.StatusCopy.NoVersion}}</p>
21 {{else}}
22 <p>{{.Deployment.ReportingText}}</p>
23 <ul>{{range .Deployment.Versions}}<li><code>{{.Version}}</code></li>{{end}}</ul>
24 {{if .Deployment.UnknownCount}}<p>{{$.StatusCopy.Partial}}</p>{{end}}
25 {{end}}
26 {{if .NextVersion}}
27 <p>{{.CandidateText}}</p>
28 {{if and $.CanPromote $.IsOwner}}
29 <form method="post" action="{{$.Base}}/apps/{{$.Detail.App}}/promote">
30 <input type="hidden" name="csrf" value="{{$.CSRF}}">
31 <input type="hidden" name="channel" value="stable">
32 <input type="hidden" name="version" value="{{.NextVersion}}">
33 <input type="hidden" name="back" value="releases">
34 <button type="submit" class="btn">Make {{.NextVersion}} live</button>
35 </form>
36 {{else if $.CanPromote}}
37 <p class="small">Only an account owner can make it live.</p>
38 {{end}}
39 {{end}}
40</section>
41{{end}}
42
43{{if .RetentionKeep}}
44<p class="small">Retention: the newest {{.RetentionKeep}} releases are kept; older releases not promoted, tagged, or recently shipped are pruned automatically.</p>
45{{end}}
46
47{{if .Versions}}
48<details class="reveal" open>
49<summary>All versions ({{len .Versions}})</summary>
50<div class="tablewrap">
51<table>
52 <tr><th>Version</th><th>Label</th><th>Kind</th><th>Built</th>{{if and .CanPromote (not .Detail.OneChannelPipeline)}}<th>Promote</th>{{end}}</tr>
53 {{range .Versions}}
54 <tr id="version-{{.Version}}">
55 <td><code>{{.Version}}</code>{{if .Tag}} <span class="chip chip-env">{{.Tag}}</span>{{end}}</td>
56 {{if .Err}}
57 <td colspan="3" class="error">{{.Err}}</td>
58 {{else}}
59 <td>{{if .Label}}{{.Label}}{{end}}{{if .Notes}}
60 <details><summary>notes</summary><pre class="changelog">{{.Notes}}</pre></details>
61 {{end}}{{if and (not .Label) (not .Notes)}}—{{end}}</td>
62 <td>{{.Kind}}</td>
63 <td>{{if .BuiltAt}}{{.BuiltAt}}{{else}}—{{end}}</td>
64 {{end}}
65 {{if and $.CanPromote (not $.Detail.OneChannelPipeline)}}<td>
66 <form method="post" action="{{$.Base}}/apps/{{$.Detail.App}}/promote">
67 <input type="hidden" name="csrf" value="{{$.CSRF}}">
68 <input type="hidden" name="version" value="{{.Version}}">
69 <input type="hidden" name="back" value="releases">
70 <select name="channel" aria-label="Channel to promote {{.Version}} to">
71 {{range $.PromoteChannels}}<option value="{{.}}">{{.}}</option>{{end}}
72 </select>
73 <button type="submit" class="btn-sm">Promote</button>
74 </form>
75 </td>{{end}}
76 </tr>
77 {{end}}
78</table>
79</div>
80</details>
81{{else}}
82<p>Nothing shipped yet. Ship your first release from your repo:</p>
83<pre><code>carlos ship --app {{.Detail.App}} --version $(git rev-parse --short HEAD) --target linux-arm64 &lt;binary&gt;
84carlos ship --app {{.Detail.App}} --kind static --version v1 &lt;site-dir&gt;</code></pre>
85<p class="small">Releases appear here once shipped, and get promoted to channels from this page.</p>
86{{end}}
87
88{{if .Detail.OneChannelPipeline}}
89<details class="reveal">
90<summary>Test versions and rolling back</summary>
91{{template "solorollback" .}}
92{{template "canaries" .}}
93{{template "apptags" .}}
94</details>
95{{else}}
96<details class="reveal">
97<summary>Release pipeline — channels, test versions, and the promotion ladder</summary>
98{{template "ladder" .}}
99
100<h2>Channels</h2>
101{{if .Detail.Channels}}
102<div class="tablewrap">
103<table>
104 <tr><th>Channel</th><th>Version</th><th>Promoted</th><th>Goes live</th><th></th></tr>
105 {{range .Detail.Channels}}
106 <tr>
107 <td>{{.Name}}</td>
108 {{if .Err}}
109 <td colspan="3" class="error">{{.Err}}</td>
110 {{else}}
111 <td><code>{{.Version}}</code>{{if .Tag}} <span class="chip chip-env">{{.Tag}}</span>{{end}}</td>
112 <td><span title="{{fmtTime .PromotedAt}}">{{ago .PromotedAt}}</span></td>
113 <td>{{if .BakedUntil.IsZero}}live now{{else}}in {{until .BakedUntil}}{{end}}{{if .FastTrack}} · delay skipped{{end}}</td>
114 {{end}}
115 <td>{{if and $.CanPromote .HasHistory (not .Err) (or $.Detail.Pipeline $.IsOwner (ne .Name "stable"))}}
116 <form method="post" action="{{$.Base}}/apps/{{$.Detail.App}}/rollback">
117 <input type="hidden" name="csrf" value="{{$.CSRF}}">
118 <input type="hidden" name="channel" value="{{.Name}}">
119 <input type="hidden" name="back" value="releases">
120 <button type="submit" class="btn-sm btn-danger">Roll back</button>
121 </form>
122 {{end}}</td>
123 </tr>
124 {{end}}
125</table>
126</div>
127<p class="small">Go-live times are estimates — each copy keeps its own clock. Rollbacks skip the delay.</p>
128{{else}}<p class="small">No channels yet — ship a release, then promote it below to create the first one.</p>{{end}}
129
130{{template "canaries" .}}
131{{template "apptags" .}}
132</details>
133{{end}}
134{{if .Detail.OneChannelPipeline}}
135<p class="small">This app has one channel — <code>carlos deploy</code> ships straight to it, with no
136promotion step in between. <a href="{{.Nav}}/apps/{{.Detail.App}}/pipeline">Set up a pipeline</a> to
137add more.</p>
138{{end}}
139{{if not .CanPromote}}<p class="small">Deploys are unavailable on this console — it has no signing key.</p>{{end}}
140{{template "bottom" .}}{{end}}
141
142{{/* The canary section and the tag list are NOT channel vocabulary, so both
143 app shapes get them: canary/* lives outside the pipeline entirely and is
144 always allowed (release pipelines v2 §2), and a tag names a release, not
145 a rung. Shared through one definition so the two shapes cannot drift into
146 different canary controls. */}}
147{{define "canaries"}}<h2>Canaries</h2>
148{{if .Detail.Canaries}}
149<div class="tablewrap">
150<table>
151 <tr><th>Name</th><th>Channel</th><th>Version</th><th>Created</th><th>URL</th><th></th></tr>
152 {{range .Detail.Canaries}}
153 <tr>
154 <td>{{.Name}}</td>
155 <td><code>{{.Channel}}</code></td>
156 {{if .Err}}
157 <td colspan="3" class="error">{{.Err}}</td>
158 {{else}}
159 <td><code>{{.Version}}</code></td>
160 <td><span title="{{fmtTime .PromotedAt}}">{{ago .PromotedAt}}</span></td>
161 <td>{{if .Hosts}}{{range .Hosts}}<a href="https://{{.}}">{{.}}</a> {{end}}{{else}}no host yet{{end}}</td>
162 {{end}}
163 <td>{{if $.CanPromote}}
164 <form method="post" action="{{$.Base}}/apps/{{$.Detail.App}}/canary/retire">
165 <input type="hidden" name="csrf" value="{{$.CSRF}}">
166 <input type="hidden" name="name" value="{{.Name}}">
167 <input type="hidden" name="back" value="releases">
168 <button type="submit" class="btn-sm btn-danger">Retire</button>
169 </form>
170 {{end}}</td>
171 </tr>
172 {{end}}
173</table>
174</div>
175{{else}}<p class="small">No test versions — a test version is a private copy serving one chosen build immediately, with no safety delay.</p>{{end}}
176{{if and .CanPromote .Versions}}
177<form class="signin" method="post" action="{{.Base}}/apps/{{.Detail.App}}/canary">
178 <input type="hidden" name="csrf" value="{{.CSRF}}">
179 <input type="hidden" name="back" value="releases">
180 <input type="text" name="name" placeholder="rc-2">
181 <select name="version">
182 {{range .Versions}}{{if not .Err}}<option value="{{.Version}}">{{.Version}}</option>{{end}}{{end}}
183 </select>
184 <button type="submit" class="btn-sm">Create canary</button>
185</form>
186<p class="small">Creates <code>canary/&lt;name&gt;</code> — a test version serving the chosen build immediately, no delay. It gets its own URL from an address that follows it:</p>
187{{if .AttachEnable}}<pre><code>{{.AttachEnable}}
188{{.AttachCmd}}</code></pre>
189<p class="small">This app has no addresses yet, so the first line sets one up under this account's platform subdomain. It comes live within a couple of minutes.</p>
190{{else}}<pre><code>{{.AttachCmd}}</code></pre>
191<p class="small">The address comes live within a couple of minutes.</p>
192{{end}}
193{{end}}{{end}}
194
195{{define "apptags"}}{{if .Tags}}
196<h2>Tags</h2>
197{{range .Tags}}
198<details>
199 <summary><code>{{.Version}}</code> — <code>{{.Release}}</code>{{if .Actor}} · {{.Actor}}{{end}}</summary>
200 <pre class="changelog">{{.Changelog}}</pre>
201</details>
202{{end}}
203{{end}}{{end}}
204
205{{/* The one-channel app's rollback control. A rollback is not channel
206 vocabulary — it is the pointer write that puts the previous build back,
207 and a one-channel app is exactly the app with no promotion step to fall
208 back on when a bad build lands. It names no channel on screen (the name
209 rides in the hidden field the door needs), draws no table and offers no
210 promote; the ladder stays hidden. RollbackChannels is empty until the
211 channel actually has somewhere to go back to. */}}
212{{define "solorollback"}}{{if .CanPromote}}{{with .Detail.RollbackChannels}}
213<h2>Rolling back</h2>
214<p class="small">Puts the previous build back in front of everyone straight away — rollbacks skip the safety delay. You'll be asked to confirm, and told which build it lands on.</p>
215{{range .}}
216<form method="post" action="{{$.Base}}/apps/{{$.Detail.App}}/rollback">
217 <input type="hidden" name="csrf" value="{{$.CSRF}}">
218 <input type="hidden" name="channel" value="{{.Name}}">
219 <input type="hidden" name="back" value="releases">
220 <button type="submit" class="btn-sm btn-danger">Roll back</button>
221</form>
222{{end}}
223{{end}}{{end}}{{end}}
224