From 216a2f54a94946147e23db7e9d9ca54ea60c82a4 Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 15:05:34 -0700 Subject: [PATCH 1/9] initial commit --- eng/templates/build.yml | 7 +++++++ settings.gradle | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/eng/templates/build.yml b/eng/templates/build.yml index 42550475..838eb061 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -11,6 +11,13 @@ jobs: steps: - checkout: self + # Authenticate to the azfunc upstream-public Azure Artifacts feed using the build identity + # (no stored secret). Writes credentials to ~/.m2/settings.xml, which settings.gradle reads. + - task: MavenAuthenticate@0 + displayName: 'Authenticate to Azure Artifacts feed' + inputs: + artifactsFeeds: upstream-public + - task: Gradle@3 inputs: # Specifies the working directory to run the Gradle build. The task uses the repository root directory if the working directory is not specified. diff --git a/settings.gradle b/settings.gradle index 03574d37..3191c762 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,44 @@ rootProject.name = 'durabletask-java' +// Resolve all dependencies through the azfunc upstream-public Azure Artifacts feed instead of +// Maven Central. PREFER_SETTINGS makes per-project mavenCentral()/oss.sonatype.org repositories +// inert so the build never reaches repo.maven.apache.org. +// +// CI auth: MavenAuthenticate@0 writes feed credentials to ~/.m2/settings.xml using the build +// identity (no stored secret). Gradle doesn't read that file, so extract the token here. When the +// file is absent (external clones / local dev), the feed is read anonymously. +def azfuncFeedUser = null +def azfuncFeedToken = null +def m2Settings = new File(System.getProperty('user.home'), '.m2/settings.xml') +if (m2Settings.exists()) { + try { + // MavenAuthenticate@0 writes a whose id is the feed name (upstream-public). + def server = new XmlSlurper().parse(m2Settings).servers.server.find { it.id.text() == 'upstream-public' } + if (server) { + azfuncFeedUser = server.username.text() + azfuncFeedToken = server.password.text() + } + } catch (Exception ignored) { + // Malformed/unreadable settings.xml: fall back to anonymous reads. + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + maven { + url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' + if (azfuncFeedToken) { + credentials { + username azfuncFeedUser ?: 'AzureDevOps' + password azfuncFeedToken + } + authentication { basic(BasicAuthentication) } + } + } + } +} + include ":client" include ":azurefunctions" include ":azuremanaged" From 3855abf6c76b8f41b9c9d10d1e14c59087b9cd8d Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 15:40:22 -0700 Subject: [PATCH 2/9] updated based on TSG example --- eng/templates/build.yml | 10 ++-------- init.gradle | 22 ++++++++++++++++++++++ settings.gradle | 39 --------------------------------------- 3 files changed, 24 insertions(+), 47 deletions(-) create mode 100644 init.gradle diff --git a/eng/templates/build.yml b/eng/templates/build.yml index 838eb061..33aa780b 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -11,13 +11,6 @@ jobs: steps: - checkout: self - # Authenticate to the azfunc upstream-public Azure Artifacts feed using the build identity - # (no stored secret). Writes credentials to ~/.m2/settings.xml, which settings.gradle reads. - - task: MavenAuthenticate@0 - displayName: 'Authenticate to Azure Artifacts feed' - inputs: - artifactsFeeds: upstream-public - - task: Gradle@3 inputs: # Specifies the working directory to run the Gradle build. The task uses the repository root directory if the working directory is not specified. @@ -31,6 +24,7 @@ jobs: jdkArchitectureOption: 'x64' publishJUnitResults: false tasks: clean assemble + options: '--init-script init.gradle' displayName: Assemble durabletask-client and durabletask-azure-functions and durabletask-azuremanaged # the secring.gpg file is required to sign the artifacts, it's generated from GnuPG, and it's stored in the library of the durabletaskframework ADO @@ -49,7 +43,7 @@ jobs: jdkVersionOption: 1.11 jdkArchitectureOption: 'x64' tasks: publish - options: '-Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' + options: '--init-script init.gradle -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' displayName: Publish durabletask-client and durabletask-azure-functions and durabletask-azuremanaged - task: CopyFiles@2 diff --git a/init.gradle b/init.gradle new file mode 100644 index 00000000..ee9b6d7e --- /dev/null +++ b/init.gradle @@ -0,0 +1,22 @@ +allprojects { + def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: findProperty('vstsMavenAccessToken') + repositories { + all { ArtifactRepository repo -> + if (repo instanceof MavenArtifactRepository && + (repo.url.toString().contains('.maven.org') || + repo.url.toString().contains('maven.apache.org') || + repo.url.toString().contains('oss.sonatype.org'))) { + remove repo + } + } + maven { + url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' + if (azfuncFeedToken) { + credentials { + username 'Azure DevOps Services' + password azfuncFeedToken + } + } + } + } +} diff --git a/settings.gradle b/settings.gradle index 3191c762..03574d37 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,44 +1,5 @@ rootProject.name = 'durabletask-java' -// Resolve all dependencies through the azfunc upstream-public Azure Artifacts feed instead of -// Maven Central. PREFER_SETTINGS makes per-project mavenCentral()/oss.sonatype.org repositories -// inert so the build never reaches repo.maven.apache.org. -// -// CI auth: MavenAuthenticate@0 writes feed credentials to ~/.m2/settings.xml using the build -// identity (no stored secret). Gradle doesn't read that file, so extract the token here. When the -// file is absent (external clones / local dev), the feed is read anonymously. -def azfuncFeedUser = null -def azfuncFeedToken = null -def m2Settings = new File(System.getProperty('user.home'), '.m2/settings.xml') -if (m2Settings.exists()) { - try { - // MavenAuthenticate@0 writes a whose id is the feed name (upstream-public). - def server = new XmlSlurper().parse(m2Settings).servers.server.find { it.id.text() == 'upstream-public' } - if (server) { - azfuncFeedUser = server.username.text() - azfuncFeedToken = server.password.text() - } - } catch (Exception ignored) { - // Malformed/unreadable settings.xml: fall back to anonymous reads. - } -} - -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) - repositories { - maven { - url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' - if (azfuncFeedToken) { - credentials { - username azfuncFeedUser ?: 'AzureDevOps' - password azfuncFeedToken - } - authentication { basic(BasicAuthentication) } - } - } - } -} - include ":client" include ":azurefunctions" include ":azuremanaged" From 3b93e157bfdd4b3e22ad74f358a9de0598811c4d Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 15:48:42 -0700 Subject: [PATCH 3/9] remove sonatype --- init.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/init.gradle b/init.gradle index ee9b6d7e..504e1891 100644 --- a/init.gradle +++ b/init.gradle @@ -4,8 +4,7 @@ allprojects { all { ArtifactRepository repo -> if (repo instanceof MavenArtifactRepository && (repo.url.toString().contains('.maven.org') || - repo.url.toString().contains('maven.apache.org') || - repo.url.toString().contains('oss.sonatype.org'))) { + repo.url.toString().contains('maven.apache.org'))) { remove repo } } From 91ebc21d1e80ecba4994f2817c47d94e6ea6b17a Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 15:59:15 -0700 Subject: [PATCH 4/9] added init.gradle to build-release-artifacts steps --- azdevops-pipeline/build-release-artifacts.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azdevops-pipeline/build-release-artifacts.yml b/azdevops-pipeline/build-release-artifacts.yml index 728dde4b..71c50a30 100644 --- a/azdevops-pipeline/build-release-artifacts.yml +++ b/azdevops-pipeline/build-release-artifacts.yml @@ -24,6 +24,7 @@ steps: jdkArchitectureOption: 'x64' publishJUnitResults: false tasks: clean assemble + options: '--init-script init.gradle' displayName: Assemble durabletask-client and durabletask-azure-functions # the secring.gpg file is required to sign the artifacts, it's generated from GnuPG, and it's stored in the library of the durabletaskframework ADO @@ -42,7 +43,7 @@ steps: jdkVersionOption: '$(jdkVersion)' jdkArchitectureOption: 'x64' tasks: publish - options: '-Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' + options: '--init-script init.gradle -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' displayName: Publish durabletask-client and durabletask-azure-functions - task: CopyFiles@2 From d89f5e2632901c7297d085166849844fcdf17604 Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 17:17:19 -0700 Subject: [PATCH 5/9] update build.yml and init.gradle --- eng/templates/build.yml | 4 ++-- init.gradle | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/eng/templates/build.yml b/eng/templates/build.yml index 33aa780b..b82304b3 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -24,7 +24,7 @@ jobs: jdkArchitectureOption: 'x64' publishJUnitResults: false tasks: clean assemble - options: '--init-script init.gradle' + options: '--init-script init.gradle --info' displayName: Assemble durabletask-client and durabletask-azure-functions and durabletask-azuremanaged # the secring.gpg file is required to sign the artifacts, it's generated from GnuPG, and it's stored in the library of the durabletaskframework ADO @@ -43,7 +43,7 @@ jobs: jdkVersionOption: 1.11 jdkArchitectureOption: 'x64' tasks: publish - options: '--init-script init.gradle -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' + options: '--init-script init.gradle --info -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' displayName: Publish durabletask-client and durabletask-azure-functions and durabletask-azuremanaged - task: CopyFiles@2 diff --git a/init.gradle b/init.gradle index 504e1891..3b93d0ad 100644 --- a/init.gradle +++ b/init.gradle @@ -1,13 +1,6 @@ allprojects { def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: findProperty('vstsMavenAccessToken') repositories { - all { ArtifactRepository repo -> - if (repo instanceof MavenArtifactRepository && - (repo.url.toString().contains('.maven.org') || - repo.url.toString().contains('maven.apache.org'))) { - remove repo - } - } maven { url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' if (azfuncFeedToken) { @@ -18,4 +11,14 @@ allprojects { } } } + // Strip public Maven Central repos after all build scripts have declared them. + // Snapshot the list first — removing while iterating repositories.all {} silently skips entries. + afterEvaluate { proj -> + def publicMavenRepos = proj.repositories.findAll { repo -> + repo instanceof MavenArtifactRepository && + (repo.url.toString().contains('.maven.org') || + repo.url.toString().contains('maven.apache.org')) + } + publicMavenRepos.each { proj.repositories.remove(it) } + } } From 70903160f243c473d0a0bb57215ce49de6592a5b Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 17:40:39 -0700 Subject: [PATCH 6/9] update settings.gradle --- settings.gradle | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/settings.gradle b/settings.gradle index 03574d37..be027482 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,21 @@ +pluginManagement { + // Feed-first so plugin-classpath artifacts (and their Gradle Module Metadata probes) + // resolve from the Azure Artifacts feed instead of being redirected to Maven Central. + def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: providers.gradleProperty('vstsMavenAccessToken').orNull + repositories { + maven { + url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' + if (azfuncFeedToken) { + credentials { + username 'Azure DevOps Services' + password azfuncFeedToken + } + } + } + gradlePluginPortal() + } +} + rootProject.name = 'durabletask-java' include ":client" From 83c8e77b5a495742afa1bfba1353a14518a70dfc Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Wed, 19 Aug 2026 22:34:51 -0700 Subject: [PATCH 7/9] remove info logging --- eng/templates/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/templates/build.yml b/eng/templates/build.yml index b82304b3..33aa780b 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -24,7 +24,7 @@ jobs: jdkArchitectureOption: 'x64' publishJUnitResults: false tasks: clean assemble - options: '--init-script init.gradle --info' + options: '--init-script init.gradle' displayName: Assemble durabletask-client and durabletask-azure-functions and durabletask-azuremanaged # the secring.gpg file is required to sign the artifacts, it's generated from GnuPG, and it's stored in the library of the durabletaskframework ADO @@ -43,7 +43,7 @@ jobs: jdkVersionOption: 1.11 jdkArchitectureOption: 'x64' tasks: publish - options: '--init-script init.gradle --info -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' + options: '--init-script init.gradle -Psigning.keyId=$(gpgSignKey) -Psigning.password=$(gpgSignPassword) -Psigning.secretKeyRingFile=$(gpgSecretFile.secureFilePath)' displayName: Publish durabletask-client and durabletask-azure-functions and durabletask-azuremanaged - task: CopyFiles@2 From 249dcbac9017a69f963e97c8bbb4b5ef27c0a6e8 Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Thu, 20 Aug 2026 12:18:34 -0700 Subject: [PATCH 8/9] Resolve gradle plugins from azure feed only; allow-list feed in init script --- init.gradle | 16 +++++++++------- settings.gradle | 4 +--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/init.gradle b/init.gradle index 3b93d0ad..d55e273e 100644 --- a/init.gradle +++ b/init.gradle @@ -1,8 +1,9 @@ allprojects { + def azfuncFeedUrl = 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: findProperty('vstsMavenAccessToken') repositories { maven { - url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' + url azfuncFeedUrl if (azfuncFeedToken) { credentials { username 'Azure DevOps Services' @@ -11,14 +12,15 @@ allprojects { } } } - // Strip public Maven Central repos after all build scripts have declared them. - // Snapshot the list first — removing while iterating repositories.all {} silently skips entries. + // Keep only the Azure Artifacts feed (and MavenLocal); remove every other Maven repository so no + // public repository can bypass the feed. afterEvaluate { proj -> - def publicMavenRepos = proj.repositories.findAll { repo -> + def isNonFeedMaven = { repo -> repo instanceof MavenArtifactRepository && - (repo.url.toString().contains('.maven.org') || - repo.url.toString().contains('maven.apache.org')) + repo.name != 'MavenLocal' && + !repo.url.toString().startsWith(azfuncFeedUrl) } - publicMavenRepos.each { proj.repositories.remove(it) } + proj.repositories.findAll(isNonFeedMaven).each { proj.repositories.remove(it) } + proj.buildscript.repositories.findAll(isNonFeedMaven).each { proj.buildscript.repositories.remove(it) } } } diff --git a/settings.gradle b/settings.gradle index be027482..6f3434a1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,5 @@ pluginManagement { - // Feed-first so plugin-classpath artifacts (and their Gradle Module Metadata probes) - // resolve from the Azure Artifacts feed instead of being redirected to Maven Central. + // Resolve plugins through the Azure Artifacts feed only. def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: providers.gradleProperty('vstsMavenAccessToken').orNull repositories { maven { @@ -12,7 +11,6 @@ pluginManagement { } } } - gradlePluginPortal() } } From 42d48ed046e011aa0f02ecbd6b48cdbc360a95fc Mon Sep 17 00:00:00 2001 From: Varshi Bachu Date: Thu, 20 Aug 2026 12:46:57 -0700 Subject: [PATCH 9/9] Gate plugin feed resolution on token; fall back to portal without it --- settings.gradle | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/settings.gradle b/settings.gradle index 6f3434a1..55a2e5e0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,15 +1,17 @@ pluginManagement { - // Resolve plugins through the Azure Artifacts feed only. + // Resolve plugins from the Azure Artifacts feed when its token is available; otherwise the public portal. def azfuncFeedToken = System.getenv('AZURE_ARTIFACTS_ENV_ACCESS_TOKEN') ?: providers.gradleProperty('vstsMavenAccessToken').orNull repositories { - maven { - url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' - if (azfuncFeedToken) { + if (azfuncFeedToken) { + maven { + url 'https://pkgs.dev.azure.com/azfunc/public/_packaging/upstream-public/maven/v1' credentials { username 'Azure DevOps Services' password azfuncFeedToken } } + } else { + gradlePluginPortal() } } }