Repository: iterative/dvc

Issue:
`dvc push --run-cache`: Remote storage run-cache does not seem to be updated
# Bug Report

## Description

When running `dvc push --run-cache`, the remote storage (S3 in my case) is not updated with the history of the runs. The output of the stages are however correctly pushed to the remote. `dvc status -c` however returns "Cache and remote '<bucket-name>' are in sync."

When manually uploading the runs to S3, `dvc pull --run-cache` is however able to detect the change and pull the run history. 

### Reproduce

1. Manual change of the code, generating a change in the output of a stage
2. dvc repro
3. dvc push --run-cache

Following the push, S3 does not seem to be updated with the "runs" folder.

### Expected

* The runs directory in S3 is updated with the runs present in the local cache

### Environment information

DVC version : 2.10.2

**Output of `dvc doctor`:**

DVC version: 2.10.2 (pip)
---------------------------------
Platform: Python 3.9.0 on Windows-10-10.0.19041-SP0
Supports:
        hdfs (fsspec = 2022.3.0, pyarrow = 8.0.0),
        webhdfs (fsspec = 2022.3.0),
        http (aiohttp = 3.8.1, aiohttp-retry = 2.4.6),
        https (aiohttp = 3.8.1, aiohttp-retry = 2.4.6),
        s3 (s3fs = 2022.3.0, boto3 = 1.21.21)
Cache types: hardlink
Cache directory: NTFS on C:\
Caches: local
Remotes: s3
Workspace directory: NTFS on C:\
Repo: dvc, git



Discussion:
Thanks for the report!

I'm able to reproduce with the latest version although not with 2.10.2. It looks like there's a regression in https://github.com/iterative/dvc/pull/7680 (cc @skshetry), although it's unclear if this is the same issue if you are using 2.10.2 and are on Windows.

Reproduction script:

```bash
#!/bin/bash
tmpdir=$(mktemp -dq)
cd $tmpdir
dvc init -q --no-scm
echo test > dep.txt
dvc stage add -n test -d dep.txt -o out.txt 'cat dep.txt > out.txt'
dvc repro
dvc remote add -d mys3 $1
dvc push --run-cache
aws s3 ls $1
aws s3 rm --recursive $1
dvc doctor
```

Output before #7680:

```console
$ bash 7718.sh s3://dvc-sandbox-temp/dave-7718/
Creating 'dvc.yaml'
Adding stage 'test' in 'dvc.yaml'
Running stage 'test':
> cat dep.txt > out.txt
Generating lock file 'dvc.lock'
Updating lock file 'dvc.lock'
Use `dvc push` to send your updates to remote storage.
Setting 'mys3' as a default remote.
2 files pushed
                           PRE d8/
                           PRE runs/
delete: s3://dvc-sandbox-temp/dave-7718/d8/e8fca2dc0f896fd7cb4cb0031ba249
delete: s3://dvc-sandbox-temp/dave-7718/runs/88/88754b06e5752ec626dca42ec609d5c065dcf2d13e8a3839a722bfda74c32ae3/1bb28a1ebd325985c349358b2631bc40dca93eaf462d6532cc2c0b45bc0c0d6b
DVC version: 2.10.3.dev6+g94c776182
---------------------------------
Platform: Python 3.10.2 on macOS-12.3.1-arm64-arm-64bit
Supports:
        azure (adlfs = 2022.4.0, knack = 0.9.0, azure-identity = 1.7.1),
        gdrive (pydrive2 = 1.10.1),
        gs (gcsfs = 2022.3.0),
        hdfs (fsspec = 2022.3.0, pyarrow = 7.0.0),
        webhdfs (fsspec = 2022.3.0),
        http (aiohttp = 3.8.1, aiohttp-retry = 2.4.5),
        https (aiohttp = 3.8.1, aiohttp-retry = 2.4.5),
        s3 (s3fs = 2022.3.0, boto3 = 1.21.21),
        ssh (sshfs = 2022.3.1),
        oss (ossfs = 2021.8.0),
        webdav (webdav4 = 0.9.4),
        webdavs (webdav4 = 0.9.4)
Cache types: reflink, hardlink, symlink
Cache directory: apfs on /dev/disk3s1s1
Caches: local
Remotes: s3
Workspace directory: apfs on /dev/disk3s1s1
Repo: dvc (no_scm)
```

Output after #7680:

```console
$ bash 7718.sh s3://dvc-sandbox-temp/dave-7718/
Creating 'dvc.yaml'
Adding stage 'test' in 'dvc.yaml'
Running stage 'test':
> cat dep.txt > out.txt
Generating lock file 'dvc.lock'
Updating lock file 'dvc.lock'
Use `dvc push` to send your updates to remote storage.
Setting 'mys3' as a default remote.
1 file pushed
                           PRE d8/
delete: s3://dvc-sandbox-temp/dave-7718/d8/e8fca2dc0f896fd7cb4cb0031ba249
DVC version: 2.10.3.dev7+g61699d1d6
---------------------------------
Platform: Python 3.10.2 on macOS-12.3.1-arm64-arm-64bit
Supports:
        azure (adlfs = 2022.4.0, knack = 0.9.0, azure-identity = 1.7.1),
        gdrive (pydrive2 = 1.10.1),
        gs (gcsfs = 2022.3.0),
        hdfs (fsspec = 2022.3.0, pyarrow = 7.0.0),
        webhdfs (fsspec = 2022.3.0),
        http (aiohttp = 3.8.1, aiohttp-retry = 2.4.5),
        https (aiohttp = 3.8.1, aiohttp-retry = 2.4.5),
        s3 (s3fs = 2022.3.0, boto3 = 1.21.21),
        ssh (sshfs = 2022.3.1),
        oss (ossfs = 2021.8.0),
        webdav (webdav4 = 0.9.4),
        webdavs (webdav4 = 0.9.4)
Cache types: reflink, hardlink, symlink
Cache directory: apfs on /dev/disk3s1s1
Caches: local
Remotes: s3
Workspace directory: apfs on /dev/disk3s1s1
Repo: dvc (no_scm)
```
@dberenbaum, yeah, looks like I made a typo 🤦🏼 😄

https://github.com/iterative/dvc/blob/7a795f79db213ef4524500bfcf93c1033726cdf4/dvc/stage/cache.py#L219

Resolving patch:
diff --git a/dvc/stage/cache.py b/dvc/stage/cache.py
--- a/dvc/stage/cache.py
+++ b/dvc/stage/cache.py
@@ -216,7 +216,7 @@ def transfer(self, from_odb, to_odb):
         from dvc.fs.callbacks import Callback
 
         from_fs = from_odb.fs
-        to_fs = from_odb.fs
+        to_fs = to_odb.fs
         func = _log_exceptions(fs.generic.copy)
         runs = from_fs.path.join(from_odb.fs_path, "runs")
 


Test patch:
diff --git a/dvc/testing/test_run_cache.py b/dvc/testing/test_run_cache.py
new file mode 100644
--- /dev/null
+++ b/dvc/testing/test_run_cache.py
@@ -0,0 +1,19 @@
+import shutil
+
+from .tmp_dir import TmpDir
+
+
+def test_push_pull(tmp_dir, dvc, remote):
+    tmp_dir.gen("foo", "foo")
+    stage = dvc.stage.add(
+        deps=["foo"], outs=["bar"], name="copy-foo-bar", cmd="cp foo bar"
+    )
+    dvc.reproduce(stage.addressing)
+    assert dvc.push(run_cache=True) == 2
+
+    stage_cache_dir = TmpDir(dvc.stage_cache.cache_dir)
+    expected = list(stage_cache_dir.rglob("*"))
+    shutil.rmtree(stage_cache_dir)
+
+    dvc.pull(run_cache=True)
+    assert list(stage_cache_dir.rglob("*")) == expected