Skip to content

feat: add support for git dependencies - #311

Open
gonzamontiel wants to merge 21 commits into
digital-asset:mainfrom
Moonsong-Labs:proposal/git-dependencies-support
Open

gonzamontiel wants to merge 21 commits into
digital-asset:mainfrom
Moonsong-Labs:proposal/git-dependencies-support

Conversation

@gonzamontiel

@gonzamontiel gonzamontiel commented Aug 21, 2026 •

Copy link
Copy Markdown

Why

dpm already resolves remote DARs from OCI. This change adds Git as a second source for pre-built .dar files, using the existing add / install / update / resolve lifecycle.

Git DARs may be declared in dependencies or data-dependencies. Mutable refs are pinned to a commit SHA in the field where they were declared. resolve then returns the cached local path (resolved-dependencies or resolved-data-dependencies).

Summary

In daml.yaml, a repo-file Git DAR is declared as git:<host>/<owner>/<repo>#<ref>?path=<file>.dar.

Example:

artifact-locations:
  "@example-repo":
    url: "git:github.com/org/repo"

dependencies:
  - git:github.com/org/repo#main?path=packages/foo.dar
  - "@example-repo#main?path=packages/bar.dar"

data-dependencies:
  - git:github.com/org/repo?release=v1.0.0&asset=foo.dar

On install / update, branch and tag refs are rewritten to a 40-character commit SHA in the same YAML field. @alias lines are authoring shorthand: pinning expands them to a full git: URI. Fetched DARs land under ~/.dpm/cache/git/<host>/<org>/<repo>/<commit-sha>/<repo-relative.dar> (release assets use a hash of tag+asset as the ref segment). resolve returns that absolute path; it does not fetch.

Repo-file fetch is any HTTPS Git host. There's also a release form ?release= which is a GitHub-only feature, since it relies on api.github.com.


Technical design

This collapsed section is the implementation and review topics for this change. It covers the feature's core (parse, fetch, pin, and resolve, including data-dependencies), lock and update, GitHub releases, and UX extras.

Details

Git dependencies core

This section implements the foundational capability: reference a pre-built .dar at a path inside a Git repository, covering parse, fetch, pin, cache, and resolve. Git DARs in data-dependencies use the same path; they land in a different YAML field and in imports.resolved-data-dependencies.

Scope

  • Parsing & validation (pkg/gitparse: parse.go, validate.go): the canonical one-liner git:<host>/<owner>/<repo>#<ref>?path=<file>.dar. Parsing also rejects mixed release / ref / path / asset, absolute / .. paths, non-.dar paths, and non-HTTPS clone URLs (SSH is rejected). file:// is test-only (DPM_TEST_ALLOW_FILE_GIT).
  • Fetch & cache (pkg/gitpuller + go-git): clone or reuse …/<repo>/.work, check out the ref, copy the .dar atomically. Empty source files and empty cache files are treated as misses. Symlinks that escape the worktree are rejected (RejectSymlinkOutsideRoot).
  • Cache layout (pkg/assistantconfig): cache/git/<host>/<org>/<repo>/<commit-sha>/…. Segments are sanitized against traversal.
  • CLI lifecycle: dpm add dar <git-uri> <--dependencies | --data-dependencies>. Exactly one flag is required. install package and resolve walk both fields. Pinning rewrites only the field that contained the entry.
  • Pinning: mutable refs are resolved and rewritten to a commit SHA in the declared YAML field at install time.
  • Aliases: artifact-locations may hold a bare git: repo URL (no #ref or query). #<ref>?path= / ?release= stay on the dependency line. A location URL that already carries # or ? is rejected.
  • Resolve: unpinned (mutable) refs and missing cache entries fail; they are not fetched. Git data-deps appear only under imports.resolved-data-dependencies.

Lock + update

Reproducibility and update semantics layered on top of the core.

Scope

  • Lockfile integration (GitLockKey / GitLockKeyForDep in pkg/gitparse): stable Git identity keys when DPM_LOCKFILE_ENABLED=true, same gate as OCI. computeExpectedLockfile still only records dependencies, not data-dependencies.
  • dpm update: re-resolves mutable refs and rewrites the pin in that field. Already-pinned SHAs are not re-resolved; they are fetched only if the cache is missing.
  • Release assets are expanded/fetched in PrepareGitDependencies (both fields) before the per-DAR update loop. The Git DAR updater does not rewrite release tags.
  • dpm update --check is implemented (see UX extras); it is not part of the mutating update path.

GitHub releases

A second transport for teams that distribute DARs as GitHub Release assets rather than in-tree files. Works in both dependencies and data-dependencies.

Scope

  • Releases API client (pkg/githubrelease): list and download release assets. Host is github.com only (plus a test override). GitLab / ?release= is rejected with a pointer to #<ref>?path=. daml.yaml is left unchanged on that rejection.
  • Expansion (pkg/damlpackage/gitrelease.go): a release line without an explicit asset expands into one dependency per .dar asset in the release. Expansion preserves wrapper shapes (main-package-id) and does not duplicate assets already listed.
  • Expansion failure rolls back daml.yaml. If expansion succeeds and a later download fails, the per-asset lines stay so retry does not re-expand.
  • Bulk fetch (pkg/gitpuller/release_fetch.go): download missing release assets during add, install, and update.
  • Release cache path: cache/git/<host>/<org>/<repo>/<sha256(tag+"\0"+asset)>/<asset>.
dependencies:
  - git:github.com/org/repo?release=v1.0.0             # expands to all .dar assets
  - git:github.com/org/repo?release=v1.0.0&asset=foo.dar

data-dependencies:
  - git:github.com/org/repo?release=v1.0.0&asset=foo.dar

UX extras

Ergonomics and operability that are convenient but not required for a functional feature.

Scope

  • Input normalization (gitnormalize): coerce alternative inputs — git:https://…, host-first shorthand, GitHub …/blob|raw/<ref>/…, and GitLab …/-/blob/<ref>/… — into the canonical one-liner. Well-known hosts for scheme-relative recognition: github.com, gitlab.com, bitbucket.org, codeberg.org. Other HTTPS hosts work when written as git:<host>/…#ref?path=….

  • dpm update --check: both fields. Passes when repo-file deps are SHA-pinned and cached, and when release assets are cached. Fails on mutable refs, missing cache, or an unexpanded ?release= line (no asset=). Non-mutating.

Coverage

The new modules pkg/gitparse, pkg/gitpuller, and pkg/githubrelease each include its own set of unit tests. Testing involving the CLI was included in dars_test.go, dpm_add_test.go, install_package_test.go, and update_git_test.go. Roughly 2.9k lines of this work is meant for coverage.

You can run the following commands to run the related tests:

go test ./pkg/gitparse ./pkg/gitpuller ./pkg/githubrelease \
        ./pkg/damlpackage ./pkg/assistantconfig \
        ./pkg/resolver ./cmd/dpm/cmd/update

go test ./cmd/dpm/cmd -run 'TestSuite/Test.*Git'

Testing

For ease of functional testing, we have prepared a demo app dpm-git-links-demo. You can checkout, run the README sequence, and play around with it.

dpm install package
dpm build
dpm test

dpm update re-resolves and re-pins refs. samples/ has the other YAML shapes: data-dependencies vs dependencies, artifact-locations aliases, and GitHub release assets.

Comment thread docs-internal/src/cli/dpm_add_dar.rst Outdated
::

dpm add dar <oci-uri> <--dependencies | --data-dependencies> [flags]
dpm add dar <oci-uri|git-uri> <--dependencies | --data-dependencies> [flags]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the dpm docs at https://github.com/canton-network/cf-docs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @hrischuk-da , thanks for the comment! the PR for the updated docs is here canton-network/cf-docs#1463

Comment thread pkg/damlpackage/locations.go Outdated
Comment on lines +36 to +39
GitRef string
DarPath string
CloneURL *url.URL
GitRelease bool

@sammy-da sammy-da Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these four fields all go hand-in-hand, right?
if so i would group them under one struct

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @sammy-da, yes, these are meant to play together, and you're right, it's cleaner having them into one struct. We'll make that change : )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0ef4cd6

Comment thread pkg/gitparse/normalize.go

@sammy-da sammy-da Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there seems to be a substantial amount of code to parse the git: urls.
i think it's big enough to warrant having its own package.

(What would be more ideal is to use an existing scheme or a library for this, if one already exists out there, rather than having to manually write this)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(for example https://github.com/hashicorp/go-getter seems to have git:: scheme)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair point on the size! it slowly grew and it’s true that now it deserves it’s own gitparse package, we’ll extract it : )

on go-getter, we looked at it but chose not to use it for two reasons: the first one being that it uses a different URL syntax than the one proposed, and most importantly, it doesn’t support parsing for GitHub release links.
in our case, adopting such a tool would mean maintaining two types of Git-line formats, and we thought that would be cumbersome

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 773d773

Comment thread pkg/damlpackage/rawdependency.go Outdated
Comment on lines +12 to +19
// GitStructuredFields is the structured git dependency form in daml.yaml.
type GitStructuredFields struct {
URL string `yaml:"url"`
Ref string `yaml:"ref"`
Path string `yaml:"path"`
Release string `yaml:"release"`
Asset string `yaml:"asset"`
}

@sammy-da sammy-da Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i believe the damlc compiler right now does not allow dependencies that are of map type in daml.yaml.

The existing code here was trying to add support for that on the dpm side for the purpose of attaching main-package-id field onto every dar specified in daml.yaml (and yes that would ideally include dars sourced from git), but that's an unfinished feature at the moment.

I would just drop this "structured git fields" feature for now, and go with the string based approach

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also fair, the feature would be really nice if damlc was aligned with it, but for the time being this syntactic sugar is gonna be gone as soon as we rewrite the line to be compliant with damlc, so yeah, we can drop it for now 👌

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 7ae6aa6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A 3.6 snapshot version of damlc has been released which now supports this syntax, and a formal 3.6 release should be coming shortly by end of month.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @dasormeter , thanks for pointing that out, do you think it's worth it to re-add the feature to this work? maybe it's better to include it as a follow up PR as this one is already big enough, wdyt ?

@tomimor

tomimor commented Sep 21, 2026

Copy link
Copy Markdown

Hi @hrischuk-da & @sammy-da! We would love to hear if you have any further feedback. Any visibility into the review timeline would be greatly appreciated as well.

We also compiled technical design decisions, feature descriptions, and testing at https://moonsong-labs.github.io/dpm/. This should add more context to this PR and hopefully help with the review process.

Thanks in advance!

This comment was marked as outdated.

Comment thread go.mod Outdated
@dasormeter

dasormeter commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

@ffarall okay now allowed for CI run of latest commit

There look to be a few tests failing on windows -- can you take a look?

you should be able to repro by running on runs-on: windows-latest on your own fork if you don't have a window machine handy to repro on
https://github.com/digital-asset/dpm/actions/runs/37046514981/job/110970327059?pr=311

There also is something wonky with perms on the Check workflow changes / workflow-policy (pull_request) check -- that is not blocking as of now but I'll try to fix separately. (that is getting fired because of the lockfile change)

@ffarall

ffarall commented Oct 2, 2026

Copy link
Copy Markdown

@ffarall okay now allowed for CI run of latest commit

There look to be a few tests failing on windows -- can you take a look?

you should be able to repro by running on runs-on: windows-latest on your own fork if you don't have a window machine handy to repro on https://github.com/digital-asset/dpm/actions/runs/37046514981/job/110970327059?pr=311

Thanks @dasormeter ! On it right now.

@dasormeter

Copy link
Copy Markdown
Contributor

There also is something wonky with perms on the Check workflow changes / workflow-policy (pull_request) check -- that is not blocking as of now but I'll try to fix separately. (that is getting fired because of the lockfile change)

the workflow policy had a syntax error which has now been corrected, so just make sure to rebase before you do your next commit on this PR

@dasormeter

Copy link
Copy Markdown
Contributor
  • Please make sure to update UNRELEASED.md with a user-friendly description of this new feature as part of this PR

@dasormeter

Copy link
Copy Markdown
Contributor

@ffarall okay now allowed for CI run of latest commit
There look to be a few tests failing on windows -- can you take a look?
you should be able to repro by running on runs-on: windows-latest on your own fork if you don't have a window machine handy to repro on https://github.com/digital-asset/dpm/actions/runs/37046514981/job/110970327059?pr=311

Thanks @dasormeter ! On it right now.

Windows test still looks to be failing after kicking off run of latest commit
https://github.com/digital-asset/dpm/actions/runs/37261358880/job/111759809275?pr=311

@dasormeter dasormeter mentioned this pull request Oct 5, 2026
@dasormeter
dasormeter requested review from dasormeter and a balanced review from Copilot October 5, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread pkg/gitparse/format.go
Comment thread pkg/packagelock/locker_git.go Outdated
Comment thread pkg/githubrelease/githubrelease.go Outdated
@dasormeter

Copy link
Copy Markdown
Contributor

The go.mod dependency changes have been separately incorporated on main, so you can now rebase this PR on main and will not get the warning on unexpected dependency changes in a fork contribution

#323

@ffarall

ffarall commented Oct 5, 2026 •

Copy link
Copy Markdown

@dasormeter Thanks for the review again! Much appreciated.

  1. Windows tests failures: the previous test failures were fixed and checked in our fork's CI run. The fix for AtomicWriteFile in 0b73c56 introduced another test that launches 8 writes of the same out.dar file. Each of the 8 write their own temp file (as the fix implemented), and then all of them try to rename the temp file to out.dar, essentially racing for it. The Windows test CI passed in our run, but didn't here in your latest run, thankfully surfacing the race condition.
    • On Unix, the rename is done in one step and each process writes in turn, being the remaining out.dar the one who renamed last.
    • On Windows, a process that tries to rename while another is renaming, will get an "Access is denied".
    • 04b5e47 includes a fix for this, where in Windows the rename is retried up to 8 times with progressively longer delays, if this error happens.
    • This should cover even 8 different dpm processes trying to concurrently write to the same .dar file. Having different dpm processes trying to write to the same .dar file concurrently would be weird enough. Having more than 8 of them would be even weirder, so we consider this fix to be sensible. Happy to discuss other options if you have some pushback.
  2. UNRELEASED.md: included description in d8ccfe1.
  3. There seem to be some issues right now with GH Actions so the Windows tests CI is queued but not running in our fork. If you prefer, I'll let you know once that's resolved and I have verified that tests pass in Windows too. I'll run it a few times to account for race conditions. Windows tests passed several times on our fork's CI.
  4. Open issues from last Copilot review addressed.

@ffarall

ffarall commented Oct 6, 2026

Copy link
Copy Markdown

@dasormeter Update. Windows tests CI has run successfully a few times in a row on our fork's CI.

@ffarall

ffarall commented Oct 6, 2026

Copy link
Copy Markdown

The Windows tests CI were failing in go tidy because of a duplicated require for the flock dependency. That's why I had to change go.mod again and it's triggering the fail in the Static checks / workflow-policy CI.

Comment thread go.mod
oras.land/oras-go/v2 v2.6.2
)

require github.com/gofrs/flock v0.13.1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should be able to remove this change now as it is already included as a dependency

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes left in go.mod 👌🏼

Windows tests and Static checks CIs passing in fork.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants