ghstack 0.9.3__tar.gz → 0.9.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. ghstack-0.9.3/README.md → ghstack-0.9.5/PKG-INFO +25 -46
  2. ghstack-0.9.3/PKG-INFO → ghstack-0.9.5/README.md +5 -72
  3. ghstack-0.9.5/pyproject.toml +49 -0
  4. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/action.py +1 -1
  5. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/checkout.py +3 -1
  6. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/cli.py +12 -6
  7. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/config.py +12 -1
  8. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/diff.py +2 -2
  9. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/forensics.py +1 -1
  10. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/github.py +1 -1
  11. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/github_utils.py +16 -2
  12. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/land.py +3 -1
  13. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/shell.py +1 -1
  14. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/status.py +1 -1
  15. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/submit.py +57 -39
  16. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/test_prelude.py +1 -1
  17. ghstack-0.9.3/LICENSE +0 -19
  18. ghstack-0.9.3/ghstack/inbox.py +0 -7
  19. ghstack-0.9.3/pyproject.toml +0 -44
  20. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/__init__.py +0 -0
  21. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/__main__.py +0 -0
  22. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/cache.py +0 -0
  23. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/circleci.py +0 -0
  24. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/circleci_real.py +0 -0
  25. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/git.py +0 -0
  26. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/github_fake.py +0 -0
  27. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/github_real.py +0 -0
  28. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/github_schema.graphql +0 -0
  29. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/gpg_sign.py +0 -0
  30. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/logs.py +0 -0
  31. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/py.typed +0 -0
  32. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/rage.py +0 -0
  33. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/types.py +0 -0
  34. {ghstack-0.9.3 → ghstack-0.9.5/src}/ghstack/unlink.py +0 -0
@@ -1,3 +1,23 @@
1
+ Metadata-Version: 2.3
2
+ Name: ghstack
3
+ Version: 0.9.5
4
+ Summary: Stack diff support for GitHub
5
+ Author: Edward Z. Yang
6
+ Author-email: Edward Z. Yang <ezyang@mit.edu>
7
+ License: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Dist: aiohttp>=3,<4
12
+ Requires-Dist: importlib-metadata>=1.4 ; python_full_version < '3.8'
13
+ Requires-Dist: requests>=2,<3
14
+ Requires-Dist: typing-extensions>=3
15
+ Requires-Dist: click>=8,<9
16
+ Requires-Dist: flake8>=7.0.0,<8.0.0
17
+ Requires-Python: >=3.8.1, <4.0.0
18
+ Project-URL: repository, https://github.com/ezyang/ghstack
19
+ Description-Content-Type: text/markdown
20
+
1
21
  # ghstack
2
22
 
3
23
  Conveniently submit stacks of diffs to GitHub as separate pull requests.
@@ -51,7 +71,11 @@ branch, and start working on a fresh branch.
51
71
 
52
72
  **WARNING.** You will NOT be able to merge these commits using the
53
73
  normal GitHub UI, as their branch bases won't be master. Use
54
- `ghstack land $PR_URL` to land a ghstack'ed pull request.
74
+ `ghstack land $PR_URL` (or alternatively `ghstack land #PR_NUM`) to land
75
+ a ghstack'ed pull request.
76
+
77
+ You can also setup a GitHub action to allow a bot land.
78
+ https://github.com/Chillee/ghstack_land_example/blob/main/.github/workflows/issue_comment.yml is an end-to-end example of how to do this.
55
79
 
56
80
  ## Structure of submitted pull requests
57
81
 
@@ -73,51 +97,6 @@ pull request and pushes commits onto three branches:
73
97
  want to work on the commits from another machine, this is the best way
74
98
  to get it.
75
99
 
76
- ## Developer notes
77
-
78
- This project uses [Poetry](https://python-poetry.org/docs/#installation), so
79
- after you've installed Poetry itself, run this command in your clone of this
80
- repo to install all the dependencies you need for working on `ghstack`:
81
- ```
82
- poetry install
83
- ```
84
- Note that this installs the dependencies (and `ghstack` itself) in an isolated
85
- Python virtual environment rather than globally. If your cwd is in your clone of
86
- this repo then you can run your locally-built `ghstack` using `poetry run
87
- ghstack $ARGS`, but if you want to run it from somewhere else, you probably want
88
- [`poetry shell`](https://python-poetry.org/docs/cli/#shell) instead:
89
- ```
90
- poetry shell
91
- cd $SOMEWHERE
92
- ghstack $ARGS
93
- ```
94
-
95
- ### Testing
96
-
97
- We have tests, using a mock GitHub GraphQL server! How cool is that?
98
- ```
99
- poetry run python test_ghstack.py
100
- ```
101
- That runs most of the tests; you can run all tests (including lints) like this:
102
- ```
103
- poetry run python run_tests.py
104
- ```
105
-
106
- ### Publishing
107
-
108
- You can also [use Poetry to
109
- publish](https://python-poetry.org/docs/cli/#publish) to a package repository.
110
- For instance, if you've configured your [Poetry
111
- repositories](https://python-poetry.org/docs/repositories/) like this:
112
- ```
113
- poetry config repositories.testpypi https://test.pypi.org/legacy/
114
- ```
115
- Then you can publish to TestPyPI like this:
116
- ```
117
- poetry publish --build --repository testpypi
118
- ```
119
- To publish to PyPI itself, just omit the `--repository` argument.
120
-
121
100
  ## Design constraints
122
101
 
123
102
  There are some weird aspects about GitHub's design which lead to unusual
@@ -1,28 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: ghstack
3
- Version: 0.9.3
4
- Summary: Stack diff support for GitHub
5
- Home-page: https://github.com/ezyang/ghstack
6
- License: MIT
7
- Author: Edward Z. Yang
8
- Author-email: ezyang@mit.edu
9
- Requires-Python: >=3.8.1,<4.0.0
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Requires-Dist: aiohttp (>=3,<4)
18
- Requires-Dist: click (>=8,<9)
19
- Requires-Dist: flake8 (>=7.0.0,<8.0.0)
20
- Requires-Dist: importlib-metadata (>=1.4) ; python_version < "3.8"
21
- Requires-Dist: requests (>=2,<3)
22
- Requires-Dist: typing-extensions (>=3,<5)
23
- Project-URL: Repository, https://github.com/ezyang/ghstack
24
- Description-Content-Type: text/markdown
25
-
26
1
  # ghstack
27
2
 
28
3
  Conveniently submit stacks of diffs to GitHub as separate pull requests.
@@ -76,7 +51,11 @@ branch, and start working on a fresh branch.
76
51
 
77
52
  **WARNING.** You will NOT be able to merge these commits using the
78
53
  normal GitHub UI, as their branch bases won't be master. Use
79
- `ghstack land $PR_URL` to land a ghstack'ed pull request.
54
+ `ghstack land $PR_URL` (or alternatively `ghstack land #PR_NUM`) to land
55
+ a ghstack'ed pull request.
56
+
57
+ You can also setup a GitHub action to allow a bot land.
58
+ https://github.com/Chillee/ghstack_land_example/blob/main/.github/workflows/issue_comment.yml is an end-to-end example of how to do this.
80
59
 
81
60
  ## Structure of submitted pull requests
82
61
 
@@ -98,51 +77,6 @@ pull request and pushes commits onto three branches:
98
77
  want to work on the commits from another machine, this is the best way
99
78
  to get it.
100
79
 
101
- ## Developer notes
102
-
103
- This project uses [Poetry](https://python-poetry.org/docs/#installation), so
104
- after you've installed Poetry itself, run this command in your clone of this
105
- repo to install all the dependencies you need for working on `ghstack`:
106
- ```
107
- poetry install
108
- ```
109
- Note that this installs the dependencies (and `ghstack` itself) in an isolated
110
- Python virtual environment rather than globally. If your cwd is in your clone of
111
- this repo then you can run your locally-built `ghstack` using `poetry run
112
- ghstack $ARGS`, but if you want to run it from somewhere else, you probably want
113
- [`poetry shell`](https://python-poetry.org/docs/cli/#shell) instead:
114
- ```
115
- poetry shell
116
- cd $SOMEWHERE
117
- ghstack $ARGS
118
- ```
119
-
120
- ### Testing
121
-
122
- We have tests, using a mock GitHub GraphQL server! How cool is that?
123
- ```
124
- poetry run python test_ghstack.py
125
- ```
126
- That runs most of the tests; you can run all tests (including lints) like this:
127
- ```
128
- poetry run python run_tests.py
129
- ```
130
-
131
- ### Publishing
132
-
133
- You can also [use Poetry to
134
- publish](https://python-poetry.org/docs/cli/#publish) to a package repository.
135
- For instance, if you've configured your [Poetry
136
- repositories](https://python-poetry.org/docs/repositories/) like this:
137
- ```
138
- poetry config repositories.testpypi https://test.pypi.org/legacy/
139
- ```
140
- Then you can publish to TestPyPI like this:
141
- ```
142
- poetry publish --build --repository testpypi
143
- ```
144
- To publish to PyPI itself, just omit the `--repository` argument.
145
-
146
80
  ## Design constraints
147
81
 
148
82
  There are some weird aspects about GitHub's design which lead to unusual
@@ -189,4 +123,3 @@ So, this is not impossible to do, but it will need some work.
189
123
  You have to work out what the real base commit is, whether
190
124
  or not you need to advance it, and also rewrite the stack rendering
191
125
  code.
192
-
@@ -0,0 +1,49 @@
1
+ [project]
2
+ authors = [
3
+ {name = "Edward Z. Yang", email = "ezyang@mit.edu"},
4
+ ]
5
+ license = {text = "MIT"}
6
+ requires-python = "<4.0.0,>=3.8.1"
7
+ dependencies = [
8
+ "aiohttp<4,>=3",
9
+ "importlib-metadata>=1.4; python_version < \"3.8\"",
10
+ "requests<3,>=2",
11
+ "typing-extensions>=3",
12
+ "click<9,>=8",
13
+ "flake8<8.0.0,>=7.0.0",
14
+ ]
15
+ name = "ghstack"
16
+ version = "0.9.5"
17
+ description = "Stack diff support for GitHub"
18
+ readme = "README.md"
19
+ classifiers = [
20
+ "Programming Language :: Python :: 3",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ ]
24
+
25
+ [project.urls]
26
+ repository = "https://github.com/ezyang/ghstack"
27
+
28
+ [project.scripts]
29
+ ghstack = "ghstack.cli:main"
30
+
31
+ [dependency-groups]
32
+ dev = [
33
+ "black<25.0.0,>=24.3.0",
34
+ "flake8<8,>=7",
35
+ "graphql-core<4,>=3",
36
+ "hypothesis<7,>=6",
37
+ "mypy<2,>=1",
38
+ "pytest<8,>=7",
39
+ "usort<2,>=1",
40
+ "ufmt<3,>=2",
41
+ "lintrunner<1.0.0,>=0.11.0",
42
+ "types-requests<3.0.0.0,>=2.31.0.10",
43
+ "pytest-xdist<4.0.0,>=3.5.0",
44
+ "expecttest<1.0.0,>=0.2.0",
45
+ ]
46
+
47
+ [build-system]
48
+ requires = ["uv_build>=0.6,<0.7"]
49
+ build-backend = "uv_build"
@@ -26,7 +26,7 @@ def main(
26
26
  }
27
27
  }
28
28
  """,
29
- **params
29
+ **params,
30
30
  )
31
31
  pr_id = pr_result["data"]["repository"]["pullRequest"]["id"]
32
32
 
@@ -15,7 +15,9 @@ def main(
15
15
  remote_name: str,
16
16
  ) -> None:
17
17
 
18
- params = ghstack.github_utils.parse_pull_request(pull_request)
18
+ params = ghstack.github_utils.parse_pull_request(
19
+ pull_request, sh=sh, remote_name=remote_name
20
+ )
19
21
  head_ref = github.get_head_ref(**params)
20
22
  orig_ref = re.sub(r"/head$", "/orig", head_ref)
21
23
  if orig_ref == head_ref:
@@ -57,7 +57,9 @@ def cli_context(
57
57
  @click.option("--force", is_flag=True, hidden=True)
58
58
  @click.option("--no-skip", is_flag=True, hidden=True)
59
59
  @click.option("--draft", is_flag=True, hidden=True)
60
- @click.option("--direct", is_flag=True, hidden=True)
60
+ @click.option(
61
+ "--direct/--no-direct", "direct_opt", is_flag=True, hidden=True, default=None
62
+ )
61
63
  @click.option("--base", "-B", default=None, hidden=True)
62
64
  @click.option("--stack/--no-stack", "-s/-S", is_flag=True, default=True, hidden=True)
63
65
  def main(
@@ -67,7 +69,7 @@ def main(
67
69
  update_fields: bool,
68
70
  short: bool,
69
71
  force: bool,
70
- direct: bool,
72
+ direct_opt: Optional[bool],
71
73
  no_skip: bool,
72
74
  draft: bool,
73
75
  base: Optional[str],
@@ -89,7 +91,7 @@ def main(
89
91
  draft=draft,
90
92
  base=base,
91
93
  stack=stack,
92
- direct=direct,
94
+ direct_opt=direct_opt,
93
95
  )
94
96
 
95
97
 
@@ -226,7 +228,11 @@ def status(pull_request: str) -> None:
226
228
  "listed in the command line.",
227
229
  )
228
230
  @click.option(
229
- "--direct", is_flag=True, help="Create stack that directly merges into master"
231
+ "--direct/--no-direct",
232
+ "direct_opt",
233
+ default=None,
234
+ is_flag=True,
235
+ help="Create stack that directly merges into master",
230
236
  )
231
237
  @click.argument(
232
238
  "revs",
@@ -240,7 +246,7 @@ def submit(
240
246
  force: bool,
241
247
  no_skip: bool,
242
248
  draft: bool,
243
- direct: bool,
249
+ direct_opt: Optional[bool],
244
250
  base: Optional[str],
245
251
  revs: Tuple[str, ...],
246
252
  stack: bool,
@@ -264,7 +270,7 @@ def submit(
264
270
  base_opt=base,
265
271
  revs=revs,
266
272
  stack=stack,
267
- direct=direct,
273
+ direct_opt=direct_opt,
268
274
  )
269
275
 
270
276
 
@@ -12,6 +12,9 @@ import requests
12
12
 
13
13
  import ghstack.logs
14
14
 
15
+ DEFAULT_GHSTACKRC_PATH = Path.home() / ".ghstackrc"
16
+ GHSTACKRC_PATH_VAR = "GHSTACKRC_PATH"
17
+
15
18
  Config = NamedTuple(
16
19
  "Config",
17
20
  [
@@ -41,6 +44,12 @@ Config = NamedTuple(
41
44
  )
42
45
 
43
46
 
47
+ def get_path_from_env_var(var_name: str) -> Optional[Path]:
48
+ if (path := os.environ.get(var_name)) is not None:
49
+ return Path(path).expanduser().resolve()
50
+ return None
51
+
52
+
44
53
  def read_config(
45
54
  *,
46
55
  request_circle_token: bool = False,
@@ -60,7 +69,9 @@ def read_config(
60
69
 
61
70
  write_back = False
62
71
  if config_path is None:
63
- config_path = os.path.expanduser("~/.ghstackrc")
72
+ config_path = str(
73
+ get_path_from_env_var(GHSTACKRC_PATH_VAR) or DEFAULT_GHSTACKRC_PATH
74
+ )
64
75
  write_back = True
65
76
 
66
77
  logging.debug(f"config_path = {config_path}")
@@ -14,7 +14,7 @@ RE_GH_METADATA = re.compile(
14
14
 
15
15
 
16
16
  RAW_PULL_REQUEST_RESOLVED = (
17
- r"Pull Request resolved: "
17
+ r"(Pull Request resolved|Pull-Request-resolved): "
18
18
  r"https://{github_url}/(?P<owner>[^/]+)/(?P<repo>[^/]+)/pull/(?P<number>[0-9]+)"
19
19
  )
20
20
 
@@ -93,7 +93,7 @@ class Diff:
93
93
  # be the same.
94
94
  source_id: str
95
95
 
96
- # The contents of 'Pull Request resolved'. This is None for
96
+ # The contents of 'Pull-Request-resolved'. This is None for
97
97
  # diffs that haven't been submitted by ghstack. For BC reasons,
98
98
  # this also accepts gh-metadata.
99
99
  pull_request_resolved: Optional[PullRequestResolved]
@@ -73,7 +73,7 @@ async def main(
73
73
  }
74
74
  }
75
75
  """,
76
- **params
76
+ **params,
77
77
  )
78
78
  nodes = r["data"]["repository"]["pullRequest"]["commits"]["nodes"]
79
79
 
@@ -38,7 +38,7 @@ class GitHubEndpoint(metaclass=ABCMeta):
38
38
  }
39
39
  }
40
40
  """,
41
- **params
41
+ **params,
42
42
  )
43
43
  r = pr_result["data"]["repository"]["pullRequest"]["headRefName"]
44
44
  assert isinstance(r, str), type(r)
@@ -27,7 +27,7 @@ def get_github_repo_name_with_owner(
27
27
  # Grovel in remotes to figure it out
28
28
  remote_url = sh.git("remote", "get-url", remote_name)
29
29
  while True:
30
- match = r"^git@{github_url}:([^/]+)/(.+?)(?:\.git)?$".format(
30
+ match = r"^git@{github_url}:/?([^/]+)/(.+?)(?:\.git)?$".format(
31
31
  github_url=github_url
32
32
  )
33
33
  m = re.match(match, remote_url)
@@ -115,9 +115,23 @@ GitHubPullRequestParams = TypedDict(
115
115
  )
116
116
 
117
117
 
118
- def parse_pull_request(pull_request: str) -> GitHubPullRequestParams:
118
+ def parse_pull_request(
119
+ pull_request: str,
120
+ *,
121
+ sh: Optional[ghstack.shell.Shell] = None,
122
+ remote_name: Optional[str] = None,
123
+ ) -> GitHubPullRequestParams:
119
124
  m = RE_PR_URL.match(pull_request)
120
125
  if not m:
126
+ # We can reconstruct the URL if just a PR number is passed
127
+ if sh is not None and remote_name is not None:
128
+ remote_url = sh.git("remote", "get-url", remote_name)
129
+ # Do not pass the shell to avoid infinite loop
130
+ try:
131
+ return parse_pull_request(remote_url + "/pull/" + pull_request)
132
+ except RuntimeError:
133
+ # Fall back on original error message
134
+ pass
121
135
  raise RuntimeError("Did not understand PR argument. PR must be URL")
122
136
 
123
137
  github_url = m.group("github_url")
@@ -57,7 +57,9 @@ def main(
57
57
  # Furthermore, the parent commits of PR are ignored: we always
58
58
  # take the canonical version of the patch from any given pr
59
59
 
60
- params = ghstack.github_utils.parse_pull_request(pull_request)
60
+ params = ghstack.github_utils.parse_pull_request(
61
+ pull_request, sh=sh, remote_name=remote_name
62
+ )
61
63
  default_branch = ghstack.github_utils.get_github_repo_info(
62
64
  github=github,
63
65
  sh=sh,
@@ -92,7 +92,7 @@ class Shell(object):
92
92
  stdin: _HANDLE = None,
93
93
  stdout: _HANDLE = subprocess.PIPE,
94
94
  exitcode: bool = False,
95
- tick: bool = False
95
+ tick: bool = False,
96
96
  ) -> _SHELL_RET:
97
97
  """
98
98
  Run a command specified by args, and return string representing
@@ -77,7 +77,7 @@ async def main(
77
77
  }
78
78
  }
79
79
  """,
80
- **params
80
+ **params,
81
81
  )
82
82
  contexts = r["data"]["repository"]["pullRequest"]["commits"]["nodes"][0]["commit"][
83
83
  "status"
@@ -341,8 +341,8 @@ class Submitter:
341
341
 
342
342
  # Instead of merging into base branch, merge directly into the appropriate
343
343
  # main or head branch. Change merge targets appropriately as PRs get
344
- # merged
345
- direct: bool = False
344
+ # merged. If None, infer whether or not the PR should be direct or not.
345
+ direct_opt: Optional[bool] = None
346
346
 
347
347
  # ~~~~~~~~~~~~~~~~~~~~~~~~
348
348
  # Computed in post init
@@ -356,6 +356,8 @@ class Submitter:
356
356
 
357
357
  base: str = dataclasses.field(init=False)
358
358
 
359
+ direct: bool = dataclasses.field(init=False)
360
+
359
361
  # ~~~~~~~~~~~~~~~~~~~~~~~~
360
362
  # Mutable state; TODO: remove me
361
363
 
@@ -405,6 +407,18 @@ class Submitter:
405
407
 
406
408
  object.__setattr__(self, "base", default_branch)
407
409
 
410
+ # Check if direct should be used, if the user didn't explicitly
411
+ # specify an option
412
+ direct = self.direct_opt
413
+ if direct is None:
414
+ direct_r = self.sh.git(
415
+ "cat-file", "-e", "HEAD:.github/ghstack_direct", exitcode=True
416
+ )
417
+ assert isinstance(direct_r, bool)
418
+ direct = direct_r
419
+
420
+ object.__setattr__(self, "direct", direct)
421
+
408
422
  # ~~~~~~~~~~~~~~~~~~~~~~~~
409
423
  # The main algorithm
410
424
 
@@ -664,7 +678,6 @@ class Submitter:
664
678
  commits_to_submit: List[ghstack.git.CommitHeader],
665
679
  commits_to_rebase: List[ghstack.git.CommitHeader],
666
680
  ) -> Tuple[Dict[GitCommitHash, DiffMeta], Dict[GitCommitHash, GitCommitHash]]:
667
-
668
681
  # Prepare diffs in reverse topological order.
669
682
  # (Reverse here is important because we must have processed parents
670
683
  # first.)
@@ -802,7 +815,7 @@ as it supports bidirectional syncing. However, there is no way to
802
815
  convert a pre-existing PR in the old style to the new format which
803
816
  supports bidirectional syncing. If you would like to blow away the old
804
817
  PR and start anew, edit the Summary in the Phabricator diff to delete
805
- the line 'Pull Request resolved' and then run ghexport again.
818
+ the line 'Pull-Request-resolved' and then run ghexport again.
806
819
  """
807
820
  )
808
821
 
@@ -819,7 +832,7 @@ the Phabricator diff page? If so, please continue to use that button
819
832
  to export your diff.
820
833
 
821
834
  If you think this is in error, edit the Summary in the Phabricator diff
822
- to delete the line 'Pull Request resolved' and then run ghexport again.
835
+ to delete the line 'Pull-Request-resolved' and then run ghexport again.
823
836
  """
824
837
  )
825
838
  else:
@@ -950,17 +963,20 @@ to disassociate the commit with the pull request, and then try again.
950
963
  commit_msg = self._update_source_id(diff.summary, elab_diff)
951
964
  else:
952
965
  # Need to insert metadata for the first time
953
- commit_msg = "".join(
954
- [
955
- f"{strip_mentions(diff.summary.rstrip())}\n\n",
956
- f"ghstack-source-id: {diff.source_id}\n",
957
- (
958
- f"ghstack-comment-id: {elab_diff.comment_id}\n"
959
- if self.direct
960
- else ""
961
- ),
962
- f"Pull Request resolved: {pull_request_resolved.url()}",
963
- ]
966
+ # TODO: Probably quicker if we reimplement reinterpret-trailers
967
+ # in Python
968
+ commit_msg = self.sh.git(
969
+ "interpret-trailers",
970
+ "--trailer",
971
+ f"ghstack-source-id: {diff.source_id}",
972
+ *(
973
+ ["--trailer", f"ghstack-comment-id: {elab_diff.comment_id}"]
974
+ if self.direct
975
+ else []
976
+ ),
977
+ "--trailer",
978
+ f"Pull-Request-resolved: {pull_request_resolved.url()}",
979
+ input=strip_mentions(diff.summary.rstrip()),
964
980
  )
965
981
 
966
982
  return DiffMeta(
@@ -1463,6 +1479,30 @@ is closed (likely due to being merged). Please rebase to upstream and try again
1463
1479
  push_branches: List[str] = []
1464
1480
  force_push_branches: List[str] = []
1465
1481
 
1482
+ for s in reversed(diffs_to_submit):
1483
+ # It is VERY important that we do base updates BEFORE real
1484
+ # head updates, otherwise GitHub will spuriously think that
1485
+ # the user pushed a number of patches as part of the PR,
1486
+ # when actually they were just from the (new) upstream
1487
+ # branch
1488
+
1489
+ for diff, b in s.push_branches:
1490
+ if b == "orig":
1491
+ q = force_push_branches
1492
+ elif b == "base":
1493
+ q = base_push_branches
1494
+ else:
1495
+ q = push_branches
1496
+ q.append(push_spec(diff, branch(s.username, s.ghnum, b)))
1497
+ # Careful! Don't push master.
1498
+ # TODO: These pushes need to be atomic (somehow)
1499
+ if base_push_branches:
1500
+ self._git_push(base_push_branches)
1501
+ if push_branches:
1502
+ self._git_push(push_branches, force=self.force)
1503
+ if force_push_branches:
1504
+ self._git_push(force_push_branches, force=True)
1505
+
1466
1506
  for s in reversed(diffs_to_submit):
1467
1507
  # NB: GraphQL API does not support modifying PRs
1468
1508
  assert not s.closed
@@ -1500,29 +1540,6 @@ is closed (likely due to being merged). Please rebase to upstream and try again
1500
1540
  body=stack_desc,
1501
1541
  )
1502
1542
 
1503
- # It is VERY important that we do base updates BEFORE real
1504
- # head updates, otherwise GitHub will spuriously think that
1505
- # the user pushed a number of patches as part of the PR,
1506
- # when actually they were just from the (new) upstream
1507
- # branch
1508
-
1509
- for diff, b in s.push_branches:
1510
- if b == "orig":
1511
- q = force_push_branches
1512
- elif b == "base":
1513
- q = base_push_branches
1514
- else:
1515
- q = push_branches
1516
- q.append(push_spec(diff, branch(s.username, s.ghnum, b)))
1517
- # Careful! Don't push master.
1518
- # TODO: These pushes need to be atomic (somehow)
1519
- if base_push_branches:
1520
- self._git_push(base_push_branches)
1521
- if push_branches:
1522
- self._git_push(push_branches)
1523
- if force_push_branches:
1524
- self._git_push(force_push_branches, force=True)
1525
-
1526
1543
  # Report what happened
1527
1544
  def format_url(s: DiffMeta) -> str:
1528
1545
  return "https://{github_url}/{owner}/{repo}/pull/{number}".format(
@@ -1784,6 +1801,7 @@ is closed (likely due to being merged). Please rebase to upstream and try again
1784
1801
  self.sh.git(
1785
1802
  "push",
1786
1803
  self.remote_name,
1804
+ "--no-verify",
1787
1805
  *(["--force"] if force else []),
1788
1806
  *branches,
1789
1807
  )
@@ -201,7 +201,7 @@ def gh_submit(
201
201
  repo_owner_opt="pytorch",
202
202
  repo_name_opt="pytorch",
203
203
  short=short,
204
- direct=self.direct,
204
+ direct_opt=self.direct,
205
205
  no_skip=no_skip,
206
206
  github_url="github.com",
207
207
  remote_name="origin",
ghstack-0.9.3/LICENSE DELETED
@@ -1,19 +0,0 @@
1
- Copyright (c) Edward Z. Yang <ezyang@mit.edu>
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all
11
- copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
- SOFTWARE.
@@ -1,7 +0,0 @@
1
- import ghstack.github
2
- import json
3
-
4
- def main(
5
- github: ghstack.github.GitHubEndpoint,
6
- ) -> None:
7
- print(json.dumps(github.get("notifications")))
@@ -1,44 +0,0 @@
1
- [tool.poetry]
2
- name = "ghstack"
3
- version = "0.9.3"
4
- authors = ["Edward Z. Yang <ezyang@mit.edu>"]
5
- description = "Stack diff support for GitHub"
6
- readme = "README.md"
7
- repository = "https://github.com/ezyang/ghstack"
8
- include = ["ghstack/py.typed"]
9
- license = "MIT"
10
- classifiers = [
11
- "Programming Language :: Python :: 3",
12
- "License :: OSI Approved :: MIT License",
13
- "Operating System :: OS Independent",
14
- ]
15
-
16
- [tool.poetry.scripts]
17
- ghstack = "ghstack.cli:main"
18
-
19
- [tool.poetry.dependencies]
20
- aiohttp = "^3"
21
- importlib-metadata = { version = ">=1.4", python = "<3.8" }
22
- python = "^3.8.1"
23
- requests = "^2"
24
- typing-extensions = ">=3 <5"
25
- click = "^8"
26
- flake8 = "^7.0.0"
27
-
28
- [tool.poetry.dev-dependencies]
29
- black = "^24.3.0"
30
- flake8 = "^7"
31
- graphql-core = "^3"
32
- hypothesis = "^6"
33
- mypy = "^1"
34
- pytest = "^7"
35
- usort = "^1"
36
- ufmt = "^2"
37
- lintrunner = "^0.11.0"
38
- types-requests = "^2.31.0.10"
39
- pytest-xdist = "^3.5.0"
40
- expecttest = "^0.2.0"
41
-
42
- [build-system]
43
- requires = ["poetry-core>=1.0.0"]
44
- build-backend = "poetry.core.masonry.api"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes