Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1999ca6ba6 |
No files matched your search
@@ -20,11 +20,6 @@ regress.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
- 2026-10-01: The hint under the app page's environment variable editor now says
|
|
||||||
changes take effect at the next deploy or rollback, in the page's warning
|
|
||||||
style, instead of asking for a container restart, which keeps the old values
|
|
||||||
(#255).
|
|
||||||
|
|
||||||
- 2026-10-01: An app with no volume mounts says on its page, and in the log of
|
- 2026-10-01: An app with no volume mounts says on its page, and in the log of
|
||||||
each deploy, that a deploy or rollback loses the files it writes and a restart
|
each deploy, that a deploy or rollback loses the files it writes and a restart
|
||||||
keeps them; the README's Volume mounts section says a deploy or rollback keeps
|
keeps them; the README's Volume mounts section says a deploy or rollback keeps
|
||||||
|
|||||||
@@ -223,7 +223,18 @@ func TestPerformCloneRemovesContainerVolumes(t *testing.T) {
|
|||||||
|
|
||||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
c := &Client{docker: dockerAPI, log: slog.Default()}
|
||||||
|
|
||||||
_, _ = c.performClone(ctx, testCloneConfig(t))
|
dir := t.TempDir()
|
||||||
|
cfg := &cloneConfig{
|
||||||
|
repoURL: "git@example.com:repo.git",
|
||||||
|
branch: mainBranch,
|
||||||
|
sshPrivateKey: "fake-key",
|
||||||
|
containerDir: filepath.Join(dir, "repo"),
|
||||||
|
hostDir: filepath.Join(dir, "repo"),
|
||||||
|
keyFile: filepath.Join(dir, "deploy_key"),
|
||||||
|
hostKeyFile: filepath.Join(dir, "deploy_key"),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = c.performClone(ctx, cfg)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case query := <-removeQuery:
|
case query := <-removeQuery:
|
||||||
@@ -237,24 +248,6 @@ func TestPerformCloneRemovesContainerVolumes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// testCloneConfig returns the settings of a clone in these tests, with its
|
|
||||||
// files in a temporary directory.
|
|
||||||
func testCloneConfig(t *testing.T) *cloneConfig {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
return &cloneConfig{
|
|
||||||
repoURL: "git@example.com:repo.git",
|
|
||||||
branch: mainBranch,
|
|
||||||
sshPrivateKey: "fake-key",
|
|
||||||
containerDir: filepath.Join(dir, "repo"),
|
|
||||||
hostDir: filepath.Join(dir, "repo"),
|
|
||||||
keyFile: filepath.Join(dir, "deploy_key"),
|
|
||||||
hostKeyFile: filepath.Join(dir, "deploy_key"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cloneCommit is the commit the fake clones in these tests check out.
|
// cloneCommit is the commit the fake clones in these tests check out.
|
||||||
const cloneCommit = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
|
const cloneCommit = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
|
||||||
|
|
||||||
@@ -556,7 +549,18 @@ func TestPerformCloneReadsFramedLogs(t *testing.T) {
|
|||||||
|
|
||||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
c := &Client{docker: dockerAPI, log: slog.Default()}
|
||||||
|
|
||||||
result, err := c.performClone(t.Context(), testCloneConfig(t))
|
dir := t.TempDir()
|
||||||
|
cfg := &cloneConfig{
|
||||||
|
repoURL: "git@example.com:repo.git",
|
||||||
|
branch: mainBranch,
|
||||||
|
sshPrivateKey: "fake-key",
|
||||||
|
containerDir: filepath.Join(dir, "repo"),
|
||||||
|
hostDir: filepath.Join(dir, "repo"),
|
||||||
|
keyFile: filepath.Join(dir, "deploy_key"),
|
||||||
|
hostKeyFile: filepath.Join(dir, "deploy_key"),
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := c.performClone(t.Context(), cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -570,43 +574,3 @@ func TestPerformCloneReadsFramedLogs(t *testing.T) {
|
|||||||
t.Errorf("got commit %q, short %q", result.CommitSHA, result.ShortSHA)
|
t.Errorf("got commit %q, short %q", result.CommitSHA, result.ShortSHA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPerformCloneFailsWithoutShortSHA runs a clone against a fake Docker API
|
|
||||||
// whose clone succeeds but prints no "SHORT_SHA:" line, and checks that the
|
|
||||||
// clone fails, since the short hash names the image the deploy builds.
|
|
||||||
func TestPerformCloneFailsWithoutShortSHA(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
srv := httptest.NewServer(http.HandlerFunc(
|
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case strings.HasSuffix(r.URL.Path, "/containers/create"):
|
|
||||||
_, _ = w.Write([]byte(`{"Id":"gitcontainer"}`))
|
|
||||||
case strings.HasSuffix(r.URL.Path, "/wait"):
|
|
||||||
_, _ = w.Write([]byte(`{"StatusCode":0}`))
|
|
||||||
case strings.HasSuffix(r.URL.Path, "/logs"):
|
|
||||||
_, _ = stdcopy.NewStdWriter(w, stdcopy.Stdout).
|
|
||||||
Write([]byte("COMMIT:" + cloneCommit + "\n"))
|
|
||||||
default:
|
|
||||||
_, _ = w.Write([]byte(`{}`))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
t.Cleanup(srv.Close)
|
|
||||||
|
|
||||||
dockerAPI, err := client.NewClientWithOpts(
|
|
||||||
client.WithHost("tcp://" + srv.Listener.Addr().String()),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
|
||||||
|
|
||||||
_, err = c.performClone(t.Context(), testCloneConfig(t))
|
|
||||||
if !errors.Is(err, ErrGitCloneFailed) {
|
|
||||||
t.Errorf("got error %v, want %v", err, ErrGitCloneFailed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package handlers_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"sneak.berlin/go/upaas/internal/service/app"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestAppPageEnvVarHint checks that the environment variable editor says
|
|
||||||
// changes take effect at the next deploy or rollback, in the warning style.
|
|
||||||
func TestAppPageEnvVarHint(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCtx := setupTestHandlers(t)
|
|
||||||
|
|
||||||
createdApp, err := testCtx.appSvc.CreateApp(t.Context(), app.CreateAppInput{
|
|
||||||
Name: "env-hint-app",
|
|
||||||
RepoURL: "git@example.com:user/env-hint-app.git",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
request := httptest.NewRequestWithContext(
|
|
||||||
t.Context(), http.MethodGet, "/apps/"+createdApp.ID, nil,
|
|
||||||
)
|
|
||||||
request = addChiURLParams(request, map[string]string{"id": createdApp.ID})
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
|
|
||||||
testCtx.handlers.HandleAppDetail().ServeHTTP(recorder, request)
|
|
||||||
|
|
||||||
require.Equal(t, http.StatusOK, recorder.Code)
|
|
||||||
assert.Contains(t, recorder.Body.String(),
|
|
||||||
`<p class="alert-warning mt-1">`+
|
|
||||||
"Environment variable changes take effect at the next deploy or rollback.</p>")
|
|
||||||
}
|
|
||||||
@@ -564,33 +564,6 @@ func TestDeploymentMarkFinished(t *testing.T) {
|
|||||||
assert.True(t, found.FinishedAt.Valid)
|
assert.True(t, found.FinishedAt.Valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDeploymentSaveStoresCommitSetAfterInsert checks that a commit set on a
|
|
||||||
// deployment after it was first saved, as a manual deploy does once the clone
|
|
||||||
// reads it, is stored by the next save.
|
|
||||||
func TestDeploymentSaveStoresCommitSetAfterInsert(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testDB, cleanup := setupTestDB(t)
|
|
||||||
defer cleanup()
|
|
||||||
|
|
||||||
app := createTestApp(t, testDB)
|
|
||||||
|
|
||||||
deployment := models.NewDeployment(testDB)
|
|
||||||
deployment.AppID = app.ID
|
|
||||||
|
|
||||||
err := deployment.Save(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
deployment.CommitSHA = sql.NullString{String: "abc123def456", Valid: true}
|
|
||||||
|
|
||||||
err = deployment.Save(context.Background())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
found, err := models.FindDeployment(context.Background(), testDB, deployment.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, "abc123def456", found.CommitSHA.String)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeploymentFindByAppID(t *testing.T) {
|
func TestDeploymentFindByAppID(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
<button type="submit" class="btn-primary text-sm">Save</button>
|
<button type="submit" class="btn-primary text-sm">Save</button>
|
||||||
<button type="button" @click="editIdx = -1" class="text-gray-500 hover:text-gray-700 text-sm">Cancel</button>
|
<button type="button" @click="editIdx = -1" class="text-gray-500 hover:text-gray-700 text-sm">Cancel</button>
|
||||||
</form>
|
</form>
|
||||||
<p class="alert-warning mt-1">Environment variable changes take effect at the next deploy or rollback.</p>
|
<p class="text-xs text-amber-600 mt-1">⚠ Container restart needed after env var changes.</p>
|
||||||
</td>
|
</td>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in new issue
Block a user