imbi-plugin-github 2.14.0__tar.gz → 2.14.1__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 (31) hide show
  1. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/PKG-INFO +2 -2
  2. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/pyproject.toml +3 -3
  3. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/deployment.py +19 -0
  4. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_deployment.py +32 -0
  5. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/uv.lock +6 -6
  6. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/.github/workflows/publish.yml +0 -0
  7. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/.github/workflows/test.yml +0 -0
  8. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/.gitignore +0 -0
  9. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/.pre-commit-config.yaml +0 -0
  10. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/CLAUDE.md +0 -0
  11. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/LICENSE +0 -0
  12. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/README.md +0 -0
  13. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/justfile +0 -0
  14. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/__init__.py +0 -0
  15. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/_app_auth.py +0 -0
  16. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/_hosts.py +0 -0
  17. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/_repos.py +0 -0
  18. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/commits.py +0 -0
  19. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/doctor.py +0 -0
  20. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/identity.py +0 -0
  21. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/lifecycle.py +0 -0
  22. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/plugin.py +0 -0
  23. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/src/imbi_plugin_github/pull_requests.py +0 -0
  24. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/__init__.py +0 -0
  25. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_commits.py +0 -0
  26. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_doctor.py +0 -0
  27. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_hosts.py +0 -0
  28. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_identity.py +0 -0
  29. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_lifecycle.py +0 -0
  30. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_pull_requests.py +0 -0
  31. {imbi_plugin_github-2.14.0 → imbi_plugin_github-2.14.1}/tests/test_repos.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: imbi-plugin-github
3
- Version: 2.14.0
3
+ Version: 2.14.1
4
4
  Summary: GitHub identity plugin for Imbi (github.com / GHEC / GHES)
5
5
  Author-email: "Gavin M. Roy" <gavinr@aweber.com>
6
6
  License: BSD-3-Clause
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.14
14
14
  Requires-Python: >=3.14
15
15
  Requires-Dist: httpx>=0.27
16
- Requires-Dist: imbi-common[databases]==2.14.0
16
+ Requires-Dist: imbi-common[databases]==2.14.1
17
17
  Requires-Dist: pydantic>=2
18
18
  Requires-Dist: pyjwt[crypto]>=2.8
19
19
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "imbi-plugin-github"
3
- version = "2.14.0"
3
+ version = "2.14.1"
4
4
  description = "GitHub identity plugin for Imbi (github.com / GHEC / GHES)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -16,7 +16,7 @@ classifiers = [
16
16
  ]
17
17
  dependencies = [
18
18
  "httpx>=0.27",
19
- "imbi-common[databases]==2.14.0",
19
+ "imbi-common[databases]==2.14.1",
20
20
  "pydantic>=2",
21
21
  "pyjwt[crypto]>=2.8",
22
22
  ]
@@ -25,7 +25,7 @@ dependencies = [
25
25
  dev = [
26
26
  "basedpyright",
27
27
  "coverage[toml]",
28
- "imbi-common[server,databases]==2.14.0",
28
+ "imbi-common[server,databases]==2.14.1",
29
29
  "pre-commit",
30
30
  "pytest",
31
31
  "pytest-asyncio",
@@ -1011,6 +1011,25 @@ class GitHubDeployment(DeploymentCapability):
1011
1011
  )
1012
1012
  return [observed for group in per_env for observed in group]
1013
1013
 
1014
+ async def get_release_notes(
1015
+ self,
1016
+ ctx: PluginContext,
1017
+ credentials: dict[str, str],
1018
+ tag: str,
1019
+ ) -> str | None:
1020
+ """Return the GitHub release body for ``tag``.
1021
+
1022
+ Tag-keyed enrichment path: the host calls this when it knows the
1023
+ release tag but not its notes -- a webhook that created the
1024
+ ``Release`` node from a deployment event (whose payload carries no
1025
+ body), or a resync whose deployment ``ref`` was a raw SHA. Opens
1026
+ a repo-scoped client and defers to :meth:`_release_notes_for_ref`,
1027
+ which 404s to ``None`` for tags without a release and caches 403s
1028
+ so a scope-limited token short-circuits.
1029
+ """
1030
+ async with self._client(ctx, credentials) as client:
1031
+ return await self._release_notes_for_ref(client, tag)
1032
+
1014
1033
  async def _list_deployments_for_env(
1015
1034
  self,
1016
1035
  client: httpx.AsyncClient,
@@ -1298,6 +1298,38 @@ class ListRecentDeploymentsTestCase(unittest.IsolatedAsyncioTestCase):
1298
1298
  self.assertEqual(first.call_count, 1)
1299
1299
 
1300
1300
 
1301
+ class GetReleaseNotesTestCase(unittest.IsolatedAsyncioTestCase):
1302
+ @respx.mock
1303
+ async def test_returns_release_body_for_tag(self) -> None:
1304
+ # The tag-keyed enrichment path: the host knows only the tag and
1305
+ # asks the plugin for the release body.
1306
+ respx.get(
1307
+ 'https://api.github.com/repos/octo/demo/releases/tags/3.23.4'
1308
+ ).mock(
1309
+ return_value=httpx.Response(
1310
+ 200,
1311
+ json={
1312
+ 'tag_name': '3.23.4',
1313
+ 'body': "## What's Changed\n- Fixed the thing",
1314
+ },
1315
+ )
1316
+ )
1317
+ plugin = GitHubDeployment()
1318
+ notes = await plugin.get_release_notes(_ctx(), _CREDS, '3.23.4')
1319
+ self.assertEqual(notes, "## What's Changed\n- Fixed the thing")
1320
+
1321
+ @respx.mock
1322
+ async def test_returns_none_when_no_release(self) -> None:
1323
+ # A tag without a GitHub release 404s and yields ``None`` so the
1324
+ # host never fails a write on a missing release.
1325
+ respx.get(
1326
+ 'https://api.github.com/repos/octo/demo/releases/tags/9.9.9'
1327
+ ).mock(return_value=httpx.Response(404, json={'message': 'Not Found'}))
1328
+ plugin = GitHubDeployment()
1329
+ notes = await plugin.get_release_notes(_ctx(), _CREDS, '9.9.9')
1330
+ self.assertIsNone(notes)
1331
+
1332
+
1301
1333
  class CheckStatusTestCase(unittest.IsolatedAsyncioTestCase):
1302
1334
  @respx.mock
1303
1335
  async def test_check_status_pass(self) -> None:
@@ -667,7 +667,7 @@ wheels = [
667
667
 
668
668
  [[package]]
669
669
  name = "imbi-common"
670
- version = "2.14.0"
670
+ version = "2.14.1"
671
671
  source = { registry = "https://pypi.org/simple" }
672
672
  dependencies = [
673
673
  { name = "cryptography" },
@@ -683,9 +683,9 @@ dependencies = [
683
683
  { name = "python-slugify" },
684
684
  { name = "typer" },
685
685
  ]
686
- sdist = { url = "https://files.pythonhosted.org/packages/61/4c/c8837aef3cbbb5e886ce51085f0bd4c315fcc8b0325fc6060b6167e25296/imbi_common-2.14.0.tar.gz", hash = "sha256:b0a8d2168e72892a51df9054ae90b4f9e1ba668a490d673c7e9077996f8635f3", size = 361115, upload-time = "2026-07-15T21:52:14.795Z" }
686
+ sdist = { url = "https://files.pythonhosted.org/packages/ca/d4/89469d23277342ab5c234e789f5545df367349914fbf7a5b21444d41e5e8/imbi_common-2.14.1.tar.gz", hash = "sha256:d2b0df3bfedf71fafcb1477bf4fe40ad4d3432d91421f2d3e51ea90a6c77d9b2", size = 361560, upload-time = "2026-07-16T22:25:17.428Z" }
687
687
  wheels = [
688
- { url = "https://files.pythonhosted.org/packages/af/17/32614176cb1772f0c973d313d2d82f43d11e6892817c868e75b9b269323c/imbi_common-2.14.0-py3-none-any.whl", hash = "sha256:34e1b05e8e165aed8e7fc61fdd2ddbbaff55f733de58ce5de4174d7bb4f93647", size = 120818, upload-time = "2026-07-15T21:52:13.461Z" },
688
+ { url = "https://files.pythonhosted.org/packages/99/dc/c92a9972d7ca02b4710a042572deba2bfba9435cb22f7faf985952dd714c/imbi_common-2.14.1-py3-none-any.whl", hash = "sha256:23e1bb4ec45bbfe26760474621c62584b85bbb4032fa7c47327ba49837476048", size = 121047, upload-time = "2026-07-16T22:25:16.006Z" },
689
689
  ]
690
690
 
691
691
  [package.optional-dependencies]
@@ -703,7 +703,7 @@ server = [
703
703
 
704
704
  [[package]]
705
705
  name = "imbi-plugin-github"
706
- version = "2.14.0"
706
+ version = "2.14.1"
707
707
  source = { editable = "." }
708
708
  dependencies = [
709
709
  { name = "httpx" },
@@ -732,7 +732,7 @@ dist = [
732
732
  [package.metadata]
733
733
  requires-dist = [
734
734
  { name = "httpx", specifier = ">=0.27" },
735
- { name = "imbi-common", extras = ["databases"], specifier = "==2.14.0" },
735
+ { name = "imbi-common", extras = ["databases"], specifier = "==2.14.1" },
736
736
  { name = "pydantic", specifier = ">=2" },
737
737
  { name = "pyjwt", extras = ["crypto"], specifier = ">=2.8" },
738
738
  ]
@@ -741,7 +741,7 @@ requires-dist = [
741
741
  dev = [
742
742
  { name = "basedpyright" },
743
743
  { name = "coverage", extras = ["toml"] },
744
- { name = "imbi-common", extras = ["server", "databases"], specifier = "==2.14.0" },
744
+ { name = "imbi-common", extras = ["server", "databases"], specifier = "==2.14.1" },
745
745
  { name = "pre-commit" },
746
746
  { name = "pytest" },
747
747
  { name = "pytest-asyncio" },