ace-git-forgejo 0.6.2 → 0.8.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/ace/git/forgejo/http_client.rb +8 -1
- data/lib/ace/git/forgejo/provider.rb +28 -0
- data/lib/ace/git/forgejo/pull_request_api.rb +27 -2
- data/lib/ace/git/forgejo/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e06e7ebace5fc96a24f3e1ea11c26a858864acc02be4ff0e8da43823fdc4a01
|
|
4
|
+
data.tar.gz: 98b6f9244d4d965302a22bd9a7ef0faf1ca91d55801043e961cc9409c66feb0f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b07df628f1428cf4599ec991429c0767c03787196e866260ce8efeebb7dc948a0adfee15d22f290b8978c1ad46205147f7b01262929f02d78b135b5449b17527
|
|
7
|
+
data.tar.gz: 3a4308e47ec2fe95cf9e2f15cc41562a3d627aab7b4466d5029334e0b0b33c280255dd7f6b0542edf8dd4d2c6f5cc1bcdffa2abde9d6b3f22a410f8dab6a75db
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Formal reviewer-owned, exact-head provider approval and read-only approval verification through the forge-neutral review flow; comments do not substitute for approval.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Publish formal approval directly at explicit commit_id instead of rebinding pending-submit; retain safe comment-free owned pending recovery, refuse unrelated pending, ignore request/team rows, and require the verified formal-review API floor.
|
|
20
|
+
|
|
21
|
+
## [0.7.0] - 2026-10-16
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Repository-bound API surface for scoped service identities: `HttpClient`/`PullRequestApi` accept an explicit `token:` (a host-installed merge receiver credential) with the `fj` keys-file lookup unchanged as the fallback, and `PullRequestApi#create_comment` attaches one PR-thread comment (the issue-served Forgejo endpoint) with the same `MutationOutcome` refusal classification as the other lifecycle mutations.
|
|
26
|
+
|
|
10
27
|
## [0.6.2] - 2026-10-08
|
|
11
28
|
|
|
12
29
|
### Fixed
|
|
@@ -20,10 +20,15 @@ module Ace
|
|
|
20
20
|
# limited to the safe GET verb — a mutation is sent at most once per
|
|
21
21
|
# call, so a lost response stays an unknown outcome.
|
|
22
22
|
class HttpClient
|
|
23
|
-
|
|
23
|
+
# `token:` injects an explicit credential for deployments whose scoped
|
|
24
|
+
# service identity is host-installed (e.g. a merge receiver reading its
|
|
25
|
+
# token from root-owned configuration) instead of the `fj` CLI keys
|
|
26
|
+
# file; when absent the fj credential governs as before.
|
|
27
|
+
def initialize(server:, timeout:, runner: nil, token: nil)
|
|
24
28
|
@target = RepositoryBinding::Target.resolve(server.url)
|
|
25
29
|
@timeout = timeout
|
|
26
30
|
@runner = runner
|
|
31
|
+
@token = token.is_a?(String) && !token.empty? ? token : nil
|
|
27
32
|
end
|
|
28
33
|
|
|
29
34
|
def paginate(suffix)
|
|
@@ -145,6 +150,8 @@ module Ace
|
|
|
145
150
|
end
|
|
146
151
|
|
|
147
152
|
def access_token!
|
|
153
|
+
return @token if @token
|
|
154
|
+
|
|
148
155
|
path = RepositoryBinding.default_keys_path
|
|
149
156
|
data = path && JSON.parse(File.read(path))
|
|
150
157
|
# fj stores credentials under the bare host (or host:port)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "ace/git/providers/formal_approval"
|
|
4
5
|
require "uri"
|
|
5
6
|
require "ace/git/atoms/server_url"
|
|
6
7
|
require_relative "cli_executor"
|
|
@@ -340,6 +341,14 @@ module Ace
|
|
|
340
341
|
raise Ace::Git::ProviderMalformedOutputError, "Malformed Forgejo repository file content: #{e.message}"
|
|
341
342
|
end
|
|
342
343
|
|
|
344
|
+
def approve_pull_request(number:, expected_head:, body:, correlation:)
|
|
345
|
+
formal_approval.approve(number: number, expected_head: expected_head, body: body, correlation: correlation)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def pull_request_approval(number:, expected_head:, review_id:)
|
|
349
|
+
formal_approval.read(number: number, expected_head: expected_head, review_id: review_id)
|
|
350
|
+
end
|
|
351
|
+
|
|
343
352
|
def create_pull_request_comment(number:, expected_head:, body:, correlation:)
|
|
344
353
|
number = request_number!(number)
|
|
345
354
|
pr = verify_expected_head!(pull_request(number: number), expected_head)
|
|
@@ -914,6 +923,25 @@ module Ace
|
|
|
914
923
|
"Cannot post review comment to PR ##{pr.number} in #{pr.state} state"
|
|
915
924
|
end
|
|
916
925
|
|
|
926
|
+
def formal_approval
|
|
927
|
+
pr_api.ensure_formal_review_supported!
|
|
928
|
+
request = lambda do |method, path, payload|
|
|
929
|
+
path = "/api/v1/user" if path == :actor
|
|
930
|
+
payload = payload.merge("event" => "APPROVED") if method == :post
|
|
931
|
+
review_http.request(method, path, body: payload)
|
|
932
|
+
end
|
|
933
|
+
Ace::Git::Providers::FormalApproval.new(provider: self, request: request,
|
|
934
|
+
list: method(:formal_review_rows), official: true, pending_reuse: true)
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
# Forgejo lists review requests alongside actual reviews. User and
|
|
938
|
+
# team requests have no reviewed commit; they are not approval evidence.
|
|
939
|
+
def formal_review_rows(path)
|
|
940
|
+
review_http.paginate(path).reject do |row|
|
|
941
|
+
row.is_a?(Hash) && row["state"] == "REQUEST_REVIEW"
|
|
942
|
+
end
|
|
943
|
+
end
|
|
944
|
+
|
|
917
945
|
def review_http
|
|
918
946
|
@review_http ||= HttpClient.new(server: server, timeout: timeout, runner: runner)
|
|
919
947
|
end
|
|
@@ -35,8 +35,8 @@ module Ace
|
|
|
35
35
|
# success), and the parsed payload when the server returned one.
|
|
36
36
|
MutationOutcome = Data.define(:status, :message, :payload)
|
|
37
37
|
|
|
38
|
-
def initialize(server:, timeout:, runner: nil)
|
|
39
|
-
@http = HttpClient.new(server: server, timeout: timeout, runner: runner)
|
|
38
|
+
def initialize(server:, timeout:, runner: nil, token: nil)
|
|
39
|
+
@http = HttpClient.new(server: server, timeout: timeout, runner: runner, token: token)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# Probe and validate the selected server's API version once per
|
|
@@ -70,9 +70,21 @@ module Ace
|
|
|
70
70
|
"Forgejo server reports #{version}; PR delivery requires #{MINIMUM_SERVER_VERSION} " \
|
|
71
71
|
"(server-enforced expected-head merge is not documented below it)"
|
|
72
72
|
end
|
|
73
|
+
@server_version = version
|
|
73
74
|
@version_supported = true
|
|
74
75
|
end
|
|
75
76
|
|
|
77
|
+
# Formal create-with-event preserves explicit commit_id in the
|
|
78
|
+
# inspected Forgejo v11.0.0 and v16.0.5 router/service/model sources.
|
|
79
|
+
# Pending submission does not: it rebinds to current HEAD and is unused.
|
|
80
|
+
def ensure_formal_review_supported!
|
|
81
|
+
ensure_version_supported!
|
|
82
|
+
unless @server_version >= Gem::Version.new("11.0.0")
|
|
83
|
+
raise Ace::Git::ProviderUnsupportedCapabilityError,
|
|
84
|
+
"Formal exact-commit approval requires Forgejo 11.0.0 or newer"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
76
88
|
# @return [Hash] the raw validated pull request payload
|
|
77
89
|
# @raise [Ace::Git::ProviderObjectNotFoundError] when absent
|
|
78
90
|
# @raise [Ace::Git::ProviderMalformedOutputError] on schema violation
|
|
@@ -161,6 +173,19 @@ module Ace
|
|
|
161
173
|
MutationOutcome.new(status: status, message: message, payload: payload)
|
|
162
174
|
end
|
|
163
175
|
|
|
176
|
+
# Attach one comment to the pull request thread (Forgejo serves PR
|
|
177
|
+
# comments on the issue endpoints) — e.g. a reviewer-produced evidence
|
|
178
|
+
# body handed over by a caller before the merge invocation.
|
|
179
|
+
#
|
|
180
|
+
# @return [MutationOutcome] 201 with the created comment payload, or a
|
|
181
|
+
# refusal outcome (404 absent pull request, 422 rejected body)
|
|
182
|
+
def create_comment(number, body)
|
|
183
|
+
status, payload, message = @http.exchange(:post, "issues/#{number}/comments",
|
|
184
|
+
body: {"body" => body.to_s})
|
|
185
|
+
classify_send!(status, "create pull request #{number} comment")
|
|
186
|
+
MutationOutcome.new(status: status, message: message, payload: payload)
|
|
187
|
+
end
|
|
188
|
+
|
|
164
189
|
private
|
|
165
190
|
|
|
166
191
|
# Authentication, absence, and transport failures classify directly
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-git-forgejo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-git
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '0.
|
|
18
|
+
version: '0.31'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '0.
|
|
25
|
+
version: '0.31'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: faraday
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|