Skip to content

Commit 4a79972

Browse files
jamengualclaude
authored andcommitted
fix: correct unlock key format to match lock key format (runatlantis#5781)
Signed-off-by: PePe Amengual <2208324+jamengual@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Ramon Vermeulen <ramonvermeulen98@gmail.com>
1 parent a3ab1ad commit 4a79972

File tree

6 files changed

+22
-16
lines changed

6 files changed

+22
-16
lines changed

server/core/db/boltdb.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ func (b *BoltDB) commandLockKey(cmdName command.Name) string {
485485
}
486486

487487
func (b *BoltDB) lockKey(p models.Project, workspace string) string {
488-
return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace)
488+
return models.GenerateLockKey(p, workspace)
489489
}
490490

491491
func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) {

server/core/locking/locking.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package locking
1818

1919
import (
2020
"errors"
21-
"fmt"
2221
"regexp"
2322
"time"
2423

@@ -146,7 +145,7 @@ func (c *Client) GetLock(key string) (*models.ProjectLock, error) {
146145
}
147146

148147
func (c *Client) key(p models.Project, workspace string) string {
149-
return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace)
148+
return models.GenerateLockKey(p, workspace)
150149
}
151150

152151
func (c *Client) lockKeyToProjectWorkspace(key string) (models.Project, string, error) {
@@ -199,5 +198,5 @@ func (c *NoOpLocker) GetLock(_ string) (*models.ProjectLock, error) {
199198
}
200199

201200
func (c *NoOpLocker) key(p models.Project, workspace string) string {
202-
return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace)
201+
return models.GenerateLockKey(p, workspace)
203202
}

server/core/redis/redis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ func (r *RedisDB) deletePull(key string) error {
414414
}
415415

416416
func (r *RedisDB) lockKey(p models.Project, workspace string) string {
417-
return fmt.Sprintf("pr/%s/%s/%s", p.RepoFullName, p.Path, workspace)
417+
return fmt.Sprintf("pr/%s", models.GenerateLockKey(p, workspace))
418418
}
419419

420420
func (r *RedisDB) commandLockKey(cmdName command.Name) string {

server/events/command_runner_test.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"errors"
1818
"fmt"
1919
"regexp"
20-
"strconv"
2120
"strings"
2221
"testing"
2322

@@ -961,13 +960,9 @@ func TestRunGenericPlanCommand_DeletePlans(t *testing.T) {
961960
When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil)
962961
testdata.Pull.BaseRepo = testdata.GithubRepo
963962
ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan})
964-
lockingLocker.VerifyWasCalledOnce().Unlock(fmt.Sprintf("%s/%d/%s/%s", testdata.Pull.BaseRepo.FullName, testdata.Pull.Num, projectCtx.ProjectName, projectCtx.Workspace))
965-
966-
lockingLocker.VerifyWasCalledOnce().
967-
Unlock(testdata.Pull.BaseRepo.FullName + "/" +
968-
strconv.Itoa(testdata.Pull.Num) + "/" +
969-
projectCtx.ProjectName + "/" +
970-
projectCtx.Workspace)
963+
// Verify that the unlock operation uses the same lock ID format as generateLockID
964+
expectedLockID := events.GenerateLockID(projectCtx)
965+
lockingLocker.VerifyWasCalledOnce().Unlock(expectedLockID)
971966
}
972967

973968
func TestRunSpecificPlanCommandDoesnt_DeletePlans(t *testing.T) {

server/events/models/models.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ type Plan struct {
276276
LocalPath string
277277
}
278278

279+
// GenerateLockKey creates a consistent lock key from a project and workspace.
280+
// This ensures the same format is used across all locking operations.
281+
func GenerateLockKey(project Project, workspace string) string {
282+
return fmt.Sprintf("%s/%s/%s", project.RepoFullName, project.Path, workspace)
283+
}
284+
279285
// NewProject constructs a Project. Use this constructor because it
280286
// sets Path correctly.
281287
func NewProject(repoFullName string, path string, projectName string) Project {

server/events/plan_command_runner.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package events
22

33
import (
4-
"strconv"
5-
64
"github.com/runatlantis/atlantis/server/core/locking"
75
"github.com/runatlantis/atlantis/server/events/command"
86
"github.com/runatlantis/atlantis/server/events/models"
97
"github.com/runatlantis/atlantis/server/events/vcs"
108
)
119

10+
// GenerateLockID creates a consistent lock ID for a project context.
11+
// This ensures the same format is used for both locking and unlocking operations.
12+
func GenerateLockID(projCtx command.ProjectContext) string {
13+
// Use models.NewProject to ensure consistent path cleaning
14+
project := models.NewProject(projCtx.BaseRepo.FullName, projCtx.RepoRelDir, "")
15+
return models.GenerateLockKey(project, projCtx.Workspace)
16+
}
17+
1218
func NewPlanCommandRunner(
1319
silenceVCSStatusNoPlans bool,
1420
silenceVCSStatusNoProjects bool,
@@ -269,7 +275,7 @@ func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) {
269275

270276
// delete lock only if there are changes
271277
ctx.Log.Info("Deleting lock for project '%s' (changes detected)", projCtx.ProjectName)
272-
lockID := projCtx.BaseRepo.FullName + "/" + strconv.Itoa(projCtx.Pull.Num) + "/" + projCtx.ProjectName + "/" + projCtx.Workspace
278+
lockID := GenerateLockID(projCtx)
273279

274280
_, err := p.lockingLocker.Unlock(lockID)
275281
if err != nil {

0 commit comments

Comments
 (0)