mirror of
https://github.com/thomiceli/opengist.git
synced 2026-08-07 07:14:49 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 72c5696cd7 | |||
| 8dce010592 | |||
| 3b5fb8f918 |
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [1.15.1](https://github.com/thomiceli/opengist/compare/v1.15.0...v1.15.1) - 2026-08-04
|
||||
See here how to [update](https://opengist.io/docs/update) Opengist.
|
||||
|
||||
### Fixed
|
||||
- Admin pagination with new URLs (#782)
|
||||
- Stop unbounded diff content growth for large files (#787)
|
||||
|
||||
## [1.15.0](https://github.com/thomiceli/opengist/compare/v1.14.0...v1.15.0) - 2026-07-30
|
||||
See here how to [update](https://opengist.io/docs/update) Opengist.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ It is similar to [GitHub Gist](https://gist.github.com/), but open-source and co
|
||||
Docker [images](https://github.com/thomiceli/opengist/pkgs/container/opengist) are available for each release :
|
||||
|
||||
```shell
|
||||
docker pull ghcr.io/thomiceli/opengist:1.15.0
|
||||
docker pull ghcr.io/thomiceli/opengist:1.15.1
|
||||
```
|
||||
|
||||
It can be used in a `docker-compose.yml` file :
|
||||
@@ -50,7 +50,7 @@ It can be used in a `docker-compose.yml` file :
|
||||
```yml
|
||||
services:
|
||||
opengist:
|
||||
image: ghcr.io/thomiceli/opengist:1.15.0
|
||||
image: ghcr.io/thomiceli/opengist:1.15.1
|
||||
container_name: opengist
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -77,9 +77,9 @@ Download the archive for your system from the release page [here](https://github
|
||||
|
||||
```shell
|
||||
# example for linux amd64
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.0/opengist1.15.0-linux-amd64.tar.gz
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.1/opengist1.15.1-linux-amd64.tar.gz
|
||||
|
||||
tar xzvf opengist1.15.0-linux-amd64.tar.gz
|
||||
tar xzvf opengist1.15.1-linux-amd64.tar.gz
|
||||
cd opengist
|
||||
chmod +x opengist
|
||||
./opengist # with or without `--config config.yml`
|
||||
|
||||
@@ -193,7 +193,7 @@ export default defineConfig({
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'v1.15.0',
|
||||
text: 'v1.15.1',
|
||||
items: [
|
||||
{ text: 'Changelog', link: '/changelog' },
|
||||
{ text: 'Releases', link: 'https://github.com/thomiceli/opengist/releases' },
|
||||
|
||||
@@ -4,9 +4,9 @@ Download the archive for your system from the release page [here](https://github
|
||||
|
||||
```shell
|
||||
# example for linux amd64
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.0/opengist1.15.0-linux-amd64.tar.gz
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.1/opengist1.15.1-linux-amd64.tar.gz
|
||||
|
||||
tar xzvf opengist1.15.0-linux-amd64.tar.gz
|
||||
tar xzvf opengist1.15.1-linux-amd64.tar.gz
|
||||
cd opengist
|
||||
chmod +x opengist
|
||||
./opengist # with or without `--config config.yml`
|
||||
|
||||
@@ -10,7 +10,7 @@ Requirements:
|
||||
git clone https://github.com/thomiceli/opengist
|
||||
cd opengist
|
||||
|
||||
git checkout v1.15.0
|
||||
git checkout v1.15.1
|
||||
|
||||
make
|
||||
./opengist
|
||||
|
||||
+2
-2
@@ -27,9 +27,9 @@ Stop the running instance; then like your first installation of Opengist, downlo
|
||||
|
||||
```shell
|
||||
# example for linux amd64
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.0/opengist1.15.0-linux-amd64.tar.gz
|
||||
wget https://github.com/thomiceli/opengist/releases/download/v1.15.1/opengist1.15.1-linux-amd64.tar.gz
|
||||
|
||||
tar xzvf opengist1.15.0-linux-amd64.tar.gz
|
||||
tar xzvf opengist1.15.1-linux-amd64.tar.gz
|
||||
cd opengist
|
||||
chmod +x opengist
|
||||
./opengist # with or without `--config config.yml`
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
# Helm Chart Changelog
|
||||
|
||||
# 0.11.0 - 2026-07-30
|
||||
|
||||
## 0.12.0 - 2026-08-04
|
||||
|
||||
- Bump Opengist image to 1.15.1
|
||||
|
||||
## 0.11.0 - 2026-07-30
|
||||
|
||||
- Bump Opengist image to 1.15.0
|
||||
- Bind strategy configuration to deployment
|
||||
|
||||
# 0.10.0 - 2026-07-21
|
||||
## 0.10.0 - 2026-07-21
|
||||
|
||||
- Bump Opengist image to 1.14.0
|
||||
|
||||
# 0.9.0 - 2026-06-10
|
||||
## 0.9.0 - 2026-06-10
|
||||
|
||||
- Bump Opengist image to 1.13.1
|
||||
|
||||
# 0.8.0 - 2026-06-09
|
||||
## 0.8.0 - 2026-06-09
|
||||
|
||||
- Bump Opengist image to 1.13.0
|
||||
|
||||
# 0.7.0 - 2026-03-14
|
||||
## 0.7.0 - 2026-03-14
|
||||
|
||||
- Bump Opengist image to 1.12.2
|
||||
- Add environment variables and secrets to statefulset
|
||||
|
||||
@@ -2,8 +2,8 @@ apiVersion: v2
|
||||
name: opengist
|
||||
description: Opengist Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.11.0
|
||||
appVersion: 1.15.0
|
||||
version: 0.12.0
|
||||
appVersion: 1.15.1
|
||||
home: https://opengist.io
|
||||
icon: https://raw.githubusercontent.com/thomiceli/opengist/master/public/img/opengist.svg
|
||||
sources:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Opengist Helm Chart
|
||||
|
||||
 
|
||||
 
|
||||
|
||||
Opengist Helm chart for Kubernetes. Check [CHANGELOG.md](CHANGELOG.md) for release notes.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ configExistingSecret: ""
|
||||
image:
|
||||
repository: ghcr.io/thomiceli/opengist
|
||||
pullPolicy: Always
|
||||
tag: "1.15.0"
|
||||
tag: "1.15.1"
|
||||
digest: ""
|
||||
imagePullSecrets: []
|
||||
# - name: "image-pull-secret"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thomiceli/opengist/internal/config"
|
||||
"os"
|
||||
@@ -189,7 +190,6 @@ func TestFork(t *testing.T) {
|
||||
require.NoError(t, err, "Could not get files of repository")
|
||||
|
||||
require.Equal(t, files1, files2, "Files are not the same")
|
||||
|
||||
}
|
||||
|
||||
func TestTruncate(t *testing.T) {
|
||||
@@ -229,6 +229,101 @@ func TestTruncate(t *testing.T) {
|
||||
require.Equal(t, 2, len(content), "Content size is not correct")
|
||||
}
|
||||
|
||||
func TestLogDiffTruncation(t *testing.T) {
|
||||
SetupTest(t)
|
||||
defer TeardownTest(t)
|
||||
|
||||
CommitToBare(t, "thomas", "gist1", map[string]string{
|
||||
"my_file.txt": "A",
|
||||
})
|
||||
|
||||
// Write enough lines to guarantee the diff content exceeds maxBytes
|
||||
// (diffSize).
|
||||
var builder strings.Builder
|
||||
lineCount := diffSize/len("A\n") + 100 // comfortably past the threshold
|
||||
for range lineCount {
|
||||
builder.WriteString("A\n")
|
||||
}
|
||||
fullContent := builder.String()
|
||||
|
||||
CommitToBare(t, "thomas", "gist1", map[string]string{
|
||||
"my_file.txt": fullContent,
|
||||
})
|
||||
|
||||
// 11 is arbitrary but comfortably above the 2 commits we expect back;
|
||||
// it just ensures GetLog isn't itself limiting the result set.
|
||||
commits, err := GetLog("thomas", "gist1", "HEAD", 0, 11)
|
||||
require.NoError(t, err, "Could not get log")
|
||||
require.Len(t, commits, 2, "Commits count are not correct")
|
||||
|
||||
// Large-file commit: content must be truncated and bounded near
|
||||
// maxBytes, not left to grow with the full file.
|
||||
largeFile := commits[0].Files[0]
|
||||
require.Len(t, commits[0].Files, 1, "Files count are not correct")
|
||||
require.True(t, largeFile.Truncated, "Diff content should be truncated for a large file")
|
||||
require.Less(t, len(largeFile.Content), len(fullContent),
|
||||
"Truncated content must be smaller than the original — content should not grow indefinitely")
|
||||
require.LessOrEqual(t, len(largeFile.Content), diffSize+len("A\n"),
|
||||
"Truncated content should be bounded at approximately maxBytes, not just under some loose multiple of it")
|
||||
|
||||
// Small-file commit: sanity check that truncation doesn't kick in
|
||||
// when it shouldn't.
|
||||
smallFile := commits[1].Files[0]
|
||||
require.False(t, smallFile.Truncated, "Small diff content should not be truncated")
|
||||
require.Equal(t, "@@ -0,0 +1 @@\n+A\n\\ No newline at end of file\n",
|
||||
smallFile.Content, "Small file content should be preserved as-is")
|
||||
}
|
||||
|
||||
// TestParseDiffContentBudget drives parseDiffContent directly, the way parseLog
|
||||
// does, with a reader sized exactly maxBytes. Going through GetLog cannot cover
|
||||
// this: a line longer than the buffer comes back from ReadLine as a fragment and
|
||||
// is drained without ever reaching the per-line clamp, so the clamp is only
|
||||
// reachable by a long line that still fits in the buffer.
|
||||
func TestParseDiffContentBudget(t *testing.T) {
|
||||
const maxBytes = 64
|
||||
|
||||
// filler emits n bytes as 2-byte lines, leaving currFileLineCount just shy
|
||||
// of the cap so the following line lands on the budget boundary.
|
||||
filler := func(b *strings.Builder, n int) {
|
||||
for range n / 2 {
|
||||
b.WriteString("A\n")
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
longLine int
|
||||
}{
|
||||
// Below the buffer size, so ReadLine returns these whole rather than as
|
||||
// fragments. Lengths straddle the point where the old code set
|
||||
// Truncated, which is why the flag was silently missed just under it.
|
||||
{"long line just under maxBytes", maxBytes - 2},
|
||||
{"long line at maxBytes-1", maxBytes - 1},
|
||||
{"long line exactly maxBytes", maxBytes},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var b strings.Builder
|
||||
filler(&b, maxBytes-2)
|
||||
b.WriteString(strings.Repeat("B", tt.longLine) + "\n")
|
||||
b.WriteString("diff --git a/x b/x\n") // ends the file's diff content
|
||||
|
||||
currentFile := &File{}
|
||||
input := bufio.NewReaderSize(strings.NewReader(b.String()), maxBytes)
|
||||
_, _, err := parseDiffContent(currentFile, maxBytes, input)
|
||||
require.NoError(t, err, "Could not parse diff content")
|
||||
|
||||
// The trailing newline of the final line is appended after the
|
||||
// budget check, so one byte of overshoot is expected.
|
||||
require.LessOrEqual(t, len(currentFile.Content), maxBytes+1,
|
||||
"Content must stay within the byte budget, not grow to a multiple of it")
|
||||
require.True(t, currentFile.Truncated,
|
||||
"Truncated must be set whenever content is clipped, otherwise the UI renders a clipped diff as complete")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitInitBranchNames(t *testing.T) {
|
||||
SetupTest(t)
|
||||
defer TeardownTest(t)
|
||||
|
||||
@@ -340,11 +340,12 @@ func parseDiffContent(currentFile *File, maxBytes int, input *bufio.Reader) (lin
|
||||
}
|
||||
}
|
||||
|
||||
if len(line) > maxBytes {
|
||||
if remaining := maxBytes - currFileLineCount; len(line) > remaining {
|
||||
currentFile.Truncated = true
|
||||
line = line[:maxBytes]
|
||||
line = line[:remaining]
|
||||
}
|
||||
currentFile.Content += line + "\n"
|
||||
currFileLineCount += len(line) + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ func AdminUsers(ctx *context.Context) error {
|
||||
return ctx.ErrorRes(500, "Cannot get users", err)
|
||||
}
|
||||
|
||||
if err = handlers.Paginate(ctx, data, pageInt, 10, "data", "admin-panel/users", 1, nil); err != nil {
|
||||
if err = handlers.Paginate(ctx, data, pageInt, 10, "data", "-/admin-panel/users", 1, nil); err != nil {
|
||||
return ctx.ErrorRes(404, ctx.Tr("error.page-not-found"), nil)
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func AdminGists(ctx *context.Context) error {
|
||||
return ctx.ErrorRes(500, "Cannot get gists", err)
|
||||
}
|
||||
|
||||
if err = handlers.Paginate(ctx, data, pageInt, 10, "data", "admin-panel/gists", 1, nil); err != nil {
|
||||
if err = handlers.Paginate(ctx, data, pageInt, 10, "data", "-/admin-panel/gists", 1, nil); err != nil {
|
||||
return ctx.ErrorRes(404, ctx.Tr("error.page-not-found"), nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -161,11 +161,11 @@ func AllGists(ctx *context.Context) error {
|
||||
|
||||
switch mode {
|
||||
case "liked":
|
||||
urlPage = fromUserStr + "/liked"
|
||||
urlPage = fromUserStr + "/-/liked"
|
||||
ctx.SetData("htmlTitle", ctx.TrH("gist.list.all-liked-by", fromUserStr))
|
||||
gists, err = db.GetAllGistsLikedByUser(fromUser.ID, currentUserId, nil, pageInt-1, sort, order, 11, 10)
|
||||
case "forked":
|
||||
urlPage = fromUserStr + "/forked"
|
||||
urlPage = fromUserStr + "/-/forked"
|
||||
ctx.SetData("htmlTitle", ctx.TrH("gist.list.all-forked-by", fromUserStr))
|
||||
gists, err = db.GetAllGistsForkedByUser(fromUser.ID, currentUserId, nil, pageInt-1, sort, order, 11, 10)
|
||||
case "fromUser":
|
||||
@@ -291,7 +291,7 @@ func Search(ctx *context.Context) error {
|
||||
renderedGists = append(renderedGists, &rendered)
|
||||
}
|
||||
|
||||
if err = handlers.Paginate(ctx, renderedGists, pageInt, 10, "gists", "search", 2, pagination); err != nil {
|
||||
if err = handlers.Paginate(ctx, renderedGists, pageInt, 10, "gists", "-/search", 2, pagination); err != nil {
|
||||
return ctx.ErrorRes(404, ctx.Tr("error.page-not-found"), nil)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user