Skip to content

Commit

Permalink
Require user confirmation before discarding changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Seb-MCaw committed Nov 5, 2024
1 parent 1469174 commit 587a1b2
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 14 deletions.
51 changes: 40 additions & 11 deletions src/alire/alire-user_pins.adb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ with Alire.VFS;

with AAA.Strings;

with CLIC.User_Input;

with GNAT.OS_Lib;

package body Alire.User_Pins is
Expand Down Expand Up @@ -216,24 +218,51 @@ package body Alire.User_Pins is
return;
end if;

-- Discard any uncommitted changes (e.g. files in 'config/' which
-- Alire has automatically generated).
-- These can cause Update's 'git pull' command to fail.

VCSs.Git.Discard_Uncommitted (Repo => Destination).Assert;

-- Finally update. In case the branch has just been changed by the
-- user in the manifest, the following call will also take care of
-- it.

Put_Info ("Pulling " & Utils.TTY.Name (Crate)
& " branch " & TTY.URL (Branch) & "...");

if not VCSs.Git.Handler.Update (Destination, Branch).Success then
Raise_Checked_Error
("Update of repository at " & TTY.URL (Destination)
& " failed, re-run with -vv -d for details");
end if;
declare
use CLIC.User_Input;
Result : Outcome := VCSs.Git.Handler.Update (Destination, Branch);
begin
if not Result.Success
and then VCSs.Git.Handler.Status (Destination) in VCSs.Git.Dirty
and then Query
(Question =>
"Do you want to discard local uncommitted changes in '"
& Destination
& "'?"
& New_Line
& "These changes were probably generated by Alire, so "
& "select 'Yes' unless you made them yourself.",
Valid => (Yes | No => True, others => False),
Default => Yes)
= Yes
then
-- One reason why the update may fail is if there are
-- uncommitted changes in the local clone which would conflict
-- with the update, so we discard such changes and try again.
--
-- This generally happens if the crate's repo tracks
-- Alire-generated files (e.g. those in 'config/'). However, it
-- is conceivable the user might have made changes to the
-- checkout in the 'alire/cache/pins' directory themselves, so
-- we require user confirmation before discarding anything.

VCSs.Git.Discard_Uncommitted (Repo => Destination).Assert;
Result := VCSs.Git.Handler.Update (Destination, Branch);
end if;

if not Result.Success then
Raise_Checked_Error
("Update of repository at " & TTY.URL (Destination)
& " failed, re-run with -vv -d for details");
end if;
end;
end Update;

begin
Expand Down
33 changes: 30 additions & 3 deletions testsuite/tests/pin/branch-update-dirty/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@


import os
import re
import subprocess

from drivers.alr import run_alr, alr_pin, init_local_crate
from drivers.asserts import assert_match, assert_in_file
from drivers.asserts import assert_match, assert_in_file, assert_not_substring
from drivers.helpers import git_branch, git_commit_file, init_git_repo


Expand Down Expand Up @@ -44,12 +45,38 @@
)
git_commit_file("Add_test_file", "test_file", "This is a new file\n")

# Check that the dirty repo doesn't prevent updating the pin
# Check that the dirty repo doesn't prevent updating the pin (subject to user
# confirmation)
os.chdir(xxx_path)
run_alr("update")
p = run_alr("update")
assert_match(
(
".*Do you want to discard local uncommitted changes in '"
rf"{re.escape(cached_yyy_path)}'\?"
".*These changes were probably generated by Alire, so select 'Yes' "
r"unless you made them yourself\."
),
p.out
)

# Check that the update was successful
assert_in_file(os.path.join(cached_yyy_path, "test_file"), "This is a new file")

# Reset the cached clone by only one commit and repeat the above. This time the
# update should work without user confirmation, as there will be no conflict
# (only 'test_file' needs to be updated).
os.chdir(cached_yyy_path)
p = subprocess.run(["git", "reset", "--hard", "HEAD~"]).check_returncode()
os.chdir(xxx_path)
run_alr("build")
os.chdir(cached_yyy_path)
p = subprocess.run(["git", "status"], capture_output=True)
p.check_returncode()
assert_match(r".*modified:\s*config/yyy_config\.gpr", p.stdout.decode())
os.chdir(xxx_path)
p = run_alr("update")
assert_not_substring("Do you want to discard local uncommitted changes", p.out)
assert_in_file(os.path.join(cached_yyy_path, "test_file"), "This is a new file")


print('SUCCESS')

0 comments on commit 587a1b2

Please sign in to comment.