Working with Forks#
When contributing to an API repository you donβt own, youβll typically work on a fork β a personal copy of the canonical repo under your own GitHub organization or user account. APX is fork-aware and handles most of this automatically, but there are important limitations around releasing.
How Fork Detection Works#
When you run apx init (or any command that needs org/repo defaults), APX inspects your git remotes:
originβ your fork (e.g.git@github.com:your-user/apis.git)upstreamβ the canonical repo (e.g.git@github.com:acme-corp/apis.git)
If both remotes exist and point to different organizations, APX assumes youβre working on a fork and automatically uses the upstream org for all consumption paths. This ensures generated import paths, go_package options, and dependency references all point to the canonical repository β not your fork.
# Your remotes
origin β git@github.com:your-user/apis.git (your fork)
upstream β git@github.com:acme-corp/apis.git (canonical)
# APX detects:
# Org = acme-corp (from upstream, not your-user)
# Repo = apis
# UpstreamOrg = acme-corp
Setting Up Your Fork#
# Fork the canonical repo on GitHub, then:
git clone git@github.com:<your-user>/apis.git
cd apis
git remote add upstream git@github.com:<canonical-org>/apis.git
# APX will now auto-detect the canonical org
apx init canonical --non-interactive
# β org: <canonical-org> (detected from upstream remote)
What Works on a Fork#
All consumption and authoring workflows work correctly on forks:
Workflow |
Status |
Details |
|---|---|---|
|
Works |
Auto-detects canonical org from upstream remote |
|
Works |
Schema validation is local |
|
Works |
Compatibility checks against local refs |
|
Works |
Code generation uses canonical import paths |
|
Works |
Displays canonical identity correctly |
|
Works |
Shows canonical |
|
Works |
Derives paths from canonical org/repo |
|
Works |
Queries the catalog |
Local development |
Works |
|
What Does NOT Work on a Fork#
Releasing from a fork is not supported. Several operations require write access to the canonical repository, which fork contributors typically donβt have:
1. apx release submit β Release Submission#
apx release submit pushes a release branch (apx/release/<api-id>/<version>) to the canonical repo and opens a PR. Fork contributors cannot push branches to a repo they donβt own.
2. apx release tag β Tag Creation#
Release tags (e.g. proto/payments/ledger/v1/v1.0.0) are created on the canonical repo by post-merge CI. Fork contributors cannot create tags on a repo they donβt own.
3. CI-Triggered Releasing#
CI workflows on your fork run with your forkβs credentials, not the canonical repoβs. Any CI step that calls apx release submit will fail because the forkβs GITHUB_TOKEN doesnβt have write access to the upstream repo.
Recommended Fork Workflow#
The correct pattern is to author on the fork, release from the canonical repoβs CI:
βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Your Fork β β Canonical Repo β
β β β β
β 1. Author schemas β β β
β 2. apx lint β β β
β 3. apx breaking β β β
β 4. apx gen go β β β
β 5. git push origin β β β
β β β β
β 6. Open PR βββββββββββββββββββ β 7. CI validates PR β
β β β 8. Reviewers approve β
β β β 9. Merge to main β
β β β 10. Post-merge CI: β
β β β - apx release finalize β
β β β - apx catalog generate β
β β β - tag creation β
βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
Steps 1β6 happen on your fork with your credentials. All consumption-side commands work because APX resolves the canonical org from your upstream remote.
Steps 7β10 happen on the canonical repoβs CI, which has the GitHub App credentials to create tags, update the catalog, and finalize releases.
Example CI Configuration (Canonical Repo)#
The canonical repo uses two workflows generated by apx init canonical:
PR validation (.github/workflows/ci.yml):
name: APX Schema CI
on:
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: infobloxopen/apx@v1
- run: apx lint
- run: apx breaking --against origin/main
Post-merge tagging and catalog (.github/workflows/on-merge.yml):
name: APX On Merge
on:
push:
branches: [main]
jobs:
tag-and-catalog:
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.APX_APP_ID }}
private-key: ${{ secrets.APX_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- uses: infobloxopen/apx@v1
- run: apx lint
- run: apx catalog generate
- run: |
git config user.name "apx-publisher[bot]"
git config user.email "apx-publisher[bot]@users.noreply.github.com"
if git diff --quiet catalog/; then
echo "No catalog changes"
else
git add catalog/
git commit -m "chore: update catalog [skip ci]"
git push
fi
See CI Templates for details on these workflows.
Troubleshooting#
APX uses my fork org instead of the canonical org#
Ensure you have an upstream remote pointing to the canonical repo:
git remote -v
# Should show:
# origin git@github.com:<your-user>/apis.git (fetch)
# upstream git@github.com:<canonical-org>/apis.git (fetch)
# If upstream is missing:
git remote add upstream git@github.com:<canonical-org>/apis.git
apx release submit fails with βpermission deniedβ#
Youβre likely running the release from a fork. Releasing must happen from the canonical repoβs CI after your PR is merged. See Recommended Fork Workflow above.
Import paths show my fork org in generated code#
This means APX didnβt detect the fork. Check that:
The
upstreamremote exists and points to the canonical repoThe
upstreamorg is different fromoriginβ APX only overrides when orgs differRun
apx inspect identityto verify the resolved org