github dont fail on force push (#6697)

This commit is contained in:
6543
2026-06-04 19:21:45 +02:00
committed by GitHub
parent 44744946ed
commit 72335fa890
5 changed files with 262 additions and 2 deletions
@@ -0,0 +1,232 @@
{
"ref": "refs/heads/main",
"before": "5ea737297f2e2e88f4cdf796e72cbcb12d40fd9c",
"after": "f7220f1f753260bf6f1c533357c70213e9fd4abe",
"repository": {
"id": 1256442359,
"node_id": "R_kgDOSuPJ9w",
"name": "oxiduct",
"full_name": "6543/oxiduct",
"private": false,
"owner": {
"name": "6543",
"email": "6543@obermui.de",
"login": "6543",
"id": 24977596,
"node_id": "MDQ6VXNlcjI0OTc3NTk2",
"avatar_url": "https://avatars.githubusercontent.com/u/24977596?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/6543",
"html_url": "https://github.com/6543",
"followers_url": "https://api.github.com/users/6543/followers",
"following_url": "https://api.github.com/users/6543/following{/other_user}",
"gists_url": "https://api.github.com/users/6543/gists{/gist_id}",
"starred_url": "https://api.github.com/users/6543/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/6543/subscriptions",
"organizations_url": "https://api.github.com/users/6543/orgs",
"repos_url": "https://api.github.com/users/6543/repos",
"events_url": "https://api.github.com/users/6543/events{/privacy}",
"received_events_url": "https://api.github.com/users/6543/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/6543/oxiduct",
"description": "Pipe traffic through oxidized steel. [tcp proxy ;)]",
"fork": false,
"url": "https://api.github.com/repos/6543/oxiduct",
"forks_url": "https://api.github.com/repos/6543/oxiduct/forks",
"keys_url": "https://api.github.com/repos/6543/oxiduct/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/6543/oxiduct/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/6543/oxiduct/teams",
"hooks_url": "https://api.github.com/repos/6543/oxiduct/hooks",
"issue_events_url": "https://api.github.com/repos/6543/oxiduct/issues/events{/number}",
"events_url": "https://api.github.com/repos/6543/oxiduct/events",
"assignees_url": "https://api.github.com/repos/6543/oxiduct/assignees{/user}",
"branches_url": "https://api.github.com/repos/6543/oxiduct/branches{/branch}",
"tags_url": "https://api.github.com/repos/6543/oxiduct/tags",
"blobs_url": "https://api.github.com/repos/6543/oxiduct/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/6543/oxiduct/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/6543/oxiduct/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/6543/oxiduct/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/6543/oxiduct/statuses/{sha}",
"languages_url": "https://api.github.com/repos/6543/oxiduct/languages",
"stargazers_url": "https://api.github.com/repos/6543/oxiduct/stargazers",
"contributors_url": "https://api.github.com/repos/6543/oxiduct/contributors",
"subscribers_url": "https://api.github.com/repos/6543/oxiduct/subscribers",
"subscription_url": "https://api.github.com/repos/6543/oxiduct/subscription",
"commits_url": "https://api.github.com/repos/6543/oxiduct/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/6543/oxiduct/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/6543/oxiduct/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/6543/oxiduct/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/6543/oxiduct/contents/{+path}",
"compare_url": "https://api.github.com/repos/6543/oxiduct/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/6543/oxiduct/merges",
"archive_url": "https://api.github.com/repos/6543/oxiduct/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/6543/oxiduct/downloads",
"issues_url": "https://api.github.com/repos/6543/oxiduct/issues{/number}",
"pulls_url": "https://api.github.com/repos/6543/oxiduct/pulls{/number}",
"milestones_url": "https://api.github.com/repos/6543/oxiduct/milestones{/number}",
"notifications_url": "https://api.github.com/repos/6543/oxiduct/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/6543/oxiduct/labels{/name}",
"releases_url": "https://api.github.com/repos/6543/oxiduct/releases{/id}",
"deployments_url": "https://api.github.com/repos/6543/oxiduct/deployments",
"created_at": 1780342272,
"updated_at": "2026-06-01T19:58:00Z",
"pushed_at": 1780343974,
"git_url": "git://github.com/6543/oxiduct.git",
"ssh_url": "git@github.com:6543/oxiduct.git",
"clone_url": "https://github.com/6543/oxiduct.git",
"svn_url": "https://github.com/6543/oxiduct",
"homepage": null,
"size": 0,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Rust",
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": {
"key": "mit",
"name": "MIT License",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit",
"node_id": "MDc6TGljZW5zZTEz"
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [],
"visibility": "public",
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "main",
"stargazers": 0,
"master_branch": "main"
},
"pusher": {
"name": "6543",
"email": "6543@obermui.de"
},
"forced": true,
"sender": {
"login": "6543",
"id": 24977596,
"node_id": "MDQ6VXNlcjI0OTc3NTk2",
"avatar_url": "https://avatars.githubusercontent.com/u/24977596?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/6543",
"html_url": "https://github.com/6543",
"followers_url": "https://api.github.com/users/6543/followers",
"following_url": "https://api.github.com/users/6543/following{/other_user}",
"gists_url": "https://api.github.com/users/6543/gists{/gist_id}",
"starred_url": "https://api.github.com/users/6543/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/6543/subscriptions",
"organizations_url": "https://api.github.com/users/6543/orgs",
"repos_url": "https://api.github.com/users/6543/repos",
"events_url": "https://api.github.com/users/6543/events{/privacy}",
"received_events_url": "https://api.github.com/users/6543/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"created": false,
"deleted": false,
"base_ref": null,
"compare": "https://github.com/6543/oxiduct/compare/5ea737297f2e...f7220f1f7532",
"commits": [
{
"id": "f7220f1f753260bf6f1c533357c70213e9fd4abe",
"tree_id": "c1f2cf4d1c9e83a01b8335b29f8d0f60eadb05db",
"distinct": true,
"message": "feat: initial implementation\n\nTCP/UDP proxy skeleton with layered dead-connection detection.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
"timestamp": "2026-06-01T21:59:22+02:00",
"url": "https://github.com/6543/oxiduct/commit/f7220f1f753260bf6f1c533357c70213e9fd4abe",
"author": {
"name": "6543",
"email": "6543@obermui.de",
"date": "2026-06-01T19:56:16Z",
"username": "6543"
},
"committer": {
"name": "6543",
"email": "6543@obermui.de",
"date": "2026-06-01T21:59:22+02:00",
"username": "6543"
},
"added": [
".clippy.toml",
".gitignore",
".woodpecker/build.yml",
".woodpecker/lint.yml",
"Cargo.lock",
"Cargo.toml",
"LICENSE",
"README.md",
"contrib/example.toml",
"rustfmt.toml",
"src/cli.rs",
"src/config.rs",
"src/main.rs",
"src/proxy/mod.rs",
"src/proxy/tcp.rs",
"src/proxy/udp.rs",
"src/socket_opts.rs"
],
"removed": [],
"modified": []
}
],
"head_commit": {
"id": "f7220f1f753260bf6f1c533357c70213e9fd4abe",
"tree_id": "c1f2cf4d1c9e83a01b8335b29f8d0f60eadb05db",
"distinct": true,
"message": "feat: initial implementation\n\nTCP/UDP proxy skeleton with layered dead-connection detection.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
"timestamp": "2026-06-01T21:59:22+02:00",
"url": "https://github.com/6543/oxiduct/commit/f7220f1f753260bf6f1c533357c70213e9fd4abe",
"author": {
"name": "6543",
"email": "6543@obermui.de",
"date": "2026-06-01T19:56:16Z",
"username": "6543"
},
"committer": {
"name": "6543",
"email": "6543@obermui.de",
"date": "2026-06-01T21:59:22+02:00",
"username": "6543"
},
"added": [
".clippy.toml",
".gitignore",
".woodpecker/build.yml",
".woodpecker/lint.yml",
"Cargo.lock",
"Cargo.toml",
"LICENSE",
"README.md",
"contrib/example.toml",
"rustfmt.toml",
"src/cli.rs",
"src/config.rs",
"src/main.rs",
"src/proxy/mod.rs",
"src/proxy/tcp.rs",
"src/proxy/udp.rs",
"src/socket_opts.rs"
],
"removed": [],
"modified": []
}
}
+7
View File
@@ -22,6 +22,13 @@ import _ "embed"
//go:embed HookPush.json
var HookPush string
// HookPushForced is a sample push hook from a force push. The "before" commit
// is unreachable after the history rewrite, so it must not be used to compare.
// https://developer.github.com/v3/activity/events/types/#pushevent
//
//go:embed HookPushForced.json
var HookPushForced string
// HookPushDeleted is a sample push hook that is marked as deleted, and is expected to be ignored.
const HookPushDeleted = `
{
+1 -2
View File
@@ -819,8 +819,7 @@ func (c *client) loadChangedFilesFromCommits(ctx context.Context, tmpRepo *model
prev = ""
fallthrough
case "":
// For tag events, prev is empty, but we can still fetch the changed files using the current commit
log.Trace().Msg("GitHub tag event, fetching changed files using current commit")
log.Trace().Msg("GitHub force push or tag event, fetching changed files using current commit")
}
repo, err := _store.GetRepoNameFallback(c.id, tmpRepo.ForgeRemoteID, tmpRepo.FullName)
+6
View File
@@ -23,6 +23,7 @@ import (
"strings"
"github.com/google/go-github/v88/github"
"github.com/rs/zerolog/log"
"go.woodpecker-ci.org/woodpecker/v3/server/forge/common"
"go.woodpecker-ci.org/woodpecker/v3/server/forge/types"
@@ -126,6 +127,11 @@ func parsePushHook(hook *github.PushEvent) (_ *model.Repo, _ *model.Pipeline, cu
return repo, pipeline, "", ""
}
if hook.GetForced() {
log.Debug().Msgf("detected force push on push hook [%d]", hook.GetPushID())
return repo, pipeline, hook.GetHeadCommit().GetID(), ""
}
return repo, pipeline, hook.GetHeadCommit().GetID(), hook.GetBefore()
}
+16
View File
@@ -80,6 +80,22 @@ func Test_parseHook(t *testing.T) {
sort.Strings(b.ChangedFiles)
})
t.Run("forced push hook", func(t *testing.T) {
// On a force push the "before" commit may be unreachable after the
// history rewrite. Comparing against it (CompareCommits) fails with a
// 404 on the forge, so the previous commit must be empty to make the
// downstream changed-files lookup fall back to the head commit only.
req := testHookRequest([]byte(fixtures.HookPushForced), hookPush)
p, r, b, cc, pc, err := parseHook(req, false)
assert.NoError(t, err)
assert.Equal(t, "f7220f1f753260bf6f1c533357c70213e9fd4abe", cc)
assert.Empty(t, pc, "forced push must not expose the unreachable before commit")
assert.Nil(t, p)
assert.NotNil(t, r)
assert.NotNil(t, b)
assert.Equal(t, model.EventPush, b.Event)
})
t.Run("PR hook", func(t *testing.T) {
req := testHookRequest([]byte(fixtures.HookPullRequest), hookPull)
p, r, b, cc, pc, err := parseHook(req, false)