diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml
index ae35e3e9f0..4ebb3905d1 100644
--- a/.github/workflows/deploy-site.yml
+++ b/.github/workflows/deploy-site.yml
@@ -18,6 +18,11 @@ on:
description: 'Tag in github/copilot-sdk monorepo (e.g., java/v1.0.1-java.0)'
type: string
required: true
+ artifact_version:
+ description: 'Java Maven artifact version. Defaults to the site version for older callers.'
+ type: string
+ required: false
+ default: ''
permissions:
contents: write
@@ -80,23 +85,29 @@ jobs:
echo "Compiling Java source from tag ${{ inputs.monorepo_tag }}"
mvn clean compile test -DskipTests=false -Dcheckstyle.skip=true -B
- # 5. Update hardcoded version strings in site content
- # Cookbook files and other markdown pages embed JBang //DEPS lines with
- # hardcoded artifact versions for direct browsing on GitHub. Update them
- # to the version being released. (${project.version} references are
- # handled by Maven resource filtering during mvn site.)
- - name: Update version strings in site content
+ # 5. Prepare Java artifact versions and snapshot repository instructions
+ - name: Prepare site artifact versions
+ env:
+ VERSION: ${{ inputs.version }}
+ ARTIFACT_VERSION_INPUT: ${{ inputs.artifact_version }}
run: |
- VERSION="${{ inputs.version }}"
- echo "Updating copilot-sdk-java version references to ${VERSION}"
- find src/site/markdown -name "*.md" -type f -exec \
- sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|copilot-sdk-java:${VERSION}|g" {} \;
+ ARTIFACT_VERSION="${ARTIFACT_VERSION_INPUT}"
+ if [[ -z "${ARTIFACT_VERSION}" ]]; then
+ if [[ "${VERSION}" == *-* ]]; then
+ echo "::error::artifact_version is required for preview documentation"
+ exit 1
+ fi
+ ARTIFACT_VERSION="${VERSION}"
+ fi
+ node scripts/prepare-site-versions.mjs \
+ "${VERSION}" "${ARTIFACT_VERSION}" src/site/markdown
+ echo "ARTIFACT_VERSION=${ARTIFACT_VERSION}" >> "$GITHUB_ENV"
# 6. Build the Maven Site using THIS repo's pom.xml + src/site/
- name: Build documentation site
run: |
- echo "Building site for version ${{ inputs.version }}"
- mvn site -Dsite.version=${{ inputs.version }} -B
+ echo "Building site for version ${{ inputs.version }} with Java artifacts ${ARTIFACT_VERSION}"
+ mvn site -Dsite.version=${{ inputs.version }} -Dartifact.version="${ARTIFACT_VERSION}" -B
# 7. Prepare gh-pages deployment directory
- name: Prepare gh-pages directory
diff --git a/pom.xml b/pom.xml
index e34688255d..cd234fd0c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,8 @@
UTF-8
0.0.0-SNAPSHOT
+
+ ${site.version}
${project.basedir}/monorepo/java
diff --git a/scripts/prepare-site-versions.mjs b/scripts/prepare-site-versions.mjs
new file mode 100644
index 0000000000..7e78127055
--- /dev/null
+++ b/scripts/prepare-site-versions.mjs
@@ -0,0 +1,117 @@
+import assert from "node:assert/strict";
+import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
+import { join } from "node:path";
+import { pathToFileURL } from "node:url";
+
+const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
+const SNAPSHOT_REPOSITORY = "https://central.sonatype.com/repository/maven-snapshots/";
+
+function markdownFiles(directory) {
+ return readdirSync(directory).flatMap((name) => {
+ const path = join(directory, name);
+ return statSync(path).isDirectory()
+ ? markdownFiles(path)
+ : path.endsWith(".md")
+ ? [path]
+ : [];
+ });
+}
+
+export function prepareSiteVersions(siteVersion, artifactVersion, markdownDirectory) {
+ assert.match(siteVersion, VERSION_PATTERN, "Invalid site version");
+ assert.match(artifactVersion, VERSION_PATTERN, "Invalid artifact version");
+ const siteBase = /^\d+\.\d+\.\d+/.exec(siteVersion)?.[0];
+ if (artifactVersion.endsWith("-SNAPSHOT")) {
+ assert.equal(
+ artifactVersion,
+ `${siteBase}-SNAPSHOT`,
+ "Snapshot artifact version must use the site version's base"
+ );
+ } else {
+ assert.equal(
+ artifactVersion,
+ siteVersion,
+ "Non-snapshot artifact version must match the site version"
+ );
+ }
+
+ const snapshot = artifactVersion.endsWith("-SNAPSHOT");
+ const replacements = new Map([
+ [
+ "",
+ snapshot
+ ? `Snapshot builds require this repository:
+
+\`\`\`xml
+
+
+ central-snapshots
+ ${SNAPSHOT_REPOSITORY}
+ false
+ true
+
+
+\`\`\``
+ : "",
+ ],
+ [
+ "",
+ snapshot
+ ? `Snapshot builds require this repository:
+
+\`\`\`groovy
+repositories {
+ mavenCentral()
+ maven {
+ url = uri('${SNAPSHOT_REPOSITORY}')
+ mavenContent { snapshotsOnly() }
+ }
+}
+\`\`\``
+ : "",
+ ],
+ [
+ "//ARTIFACT_REPOSITORY",
+ snapshot ? `//REPOS central,central-snapshots=${SNAPSHOT_REPOSITORY}` : "",
+ ],
+ ]);
+
+ let hardcodedCoordinates = 0;
+ const markerCounts = new Map([...replacements.keys()].map((marker) => [marker, 0]));
+ for (const path of markdownFiles(markdownDirectory)) {
+ let content = readFileSync(path, "utf8");
+ content = content.replace(
+ /copilot-sdk-java:\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?/g,
+ () => {
+ hardcodedCoordinates++;
+ return `copilot-sdk-java:${artifactVersion}`;
+ }
+ );
+ if (snapshot) {
+ const dependency = `//DEPS com.github:copilot-sdk-java:${artifactVersion}`;
+ content = content.replaceAll(
+ dependency,
+ `//REPOS central,central-snapshots=${SNAPSHOT_REPOSITORY}\n${dependency}`
+ );
+ }
+ for (const [marker, replacement] of replacements) {
+ const count = content.split(marker).length - 1;
+ markerCounts.set(marker, markerCounts.get(marker) + count);
+ content = content.replaceAll(marker, replacement);
+ }
+ writeFileSync(path, content);
+ }
+ assert(hardcodedCoordinates > 0, "Expected hardcoded Java coordinates in site content");
+ for (const [marker, count] of markerCounts) {
+ assert(count > 0, `Expected site marker: ${marker}`);
+ }
+}
+
+if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
+ assert.equal(
+ process.argv.length,
+ 5,
+ "Usage: prepare-site-versions.mjs "
+ );
+ prepareSiteVersions(process.argv[2], process.argv[3], process.argv[4]);
+}
diff --git a/scripts/prepare-site-versions.test.mjs b/scripts/prepare-site-versions.test.mjs
new file mode 100644
index 0000000000..5a4eb5c918
--- /dev/null
+++ b/scripts/prepare-site-versions.test.mjs
@@ -0,0 +1,74 @@
+import assert from "node:assert/strict";
+import { cpSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
+import { tmpdir } from "node:os";
+import { join, resolve } from "node:path";
+import test from "node:test";
+import { prepareSiteVersions } from "./prepare-site-versions.mjs";
+
+function fixture(t) {
+ const root = mkdtempSync(join(tmpdir(), "copilot-java-site-"));
+ t.after(() => rmSync(root, { recursive: true, force: true }));
+ const markdown = join(root, "markdown");
+ cpSync(resolve("src/site/markdown"), markdown, { recursive: true });
+ return markdown;
+}
+
+test("renders preview dependency coordinates and snapshot repositories", (t) => {
+ const markdown = fixture(t);
+ prepareSiteVersions("1.0.15-preview.2", "1.0.15-SNAPSHOT", markdown);
+
+ const gettingStarted = readFileSync(join(markdown, "getting-started.md"), "utf8");
+ assert.match(gettingStarted, /\$\{artifact\.version\}<\/version>/);
+ assert.match(gettingStarted, /implementation 'com\.github:copilot-sdk-java:\$\{artifact\.version\}'/);
+ assert.match(gettingStarted, /false<\/enabled><\/releases>/);
+ assert.match(gettingStarted, /mavenContent \{ snapshotsOnly\(\) \}/);
+ assert.match(
+ gettingStarted,
+ /\/\/REPOS central,central-snapshots=https:\/\/central\.sonatype\.com\/repository\/maven-snapshots\//
+ );
+ const cookbook = readFileSync(join(markdown, "cookbook", "managing-local-files.md"), "utf8");
+ assert.match(cookbook, /copilot-sdk-java:1\.0\.15-SNAPSHOT/);
+ for (const match of cookbook.matchAll(/\/\/DEPS com\.github:copilot-sdk-java:1\.0\.15-SNAPSHOT/g)) {
+ assert.equal(
+ cookbook.slice(0, match.index).trimEnd().split("\n").at(-1),
+ "//REPOS central,central-snapshots=https://central.sonatype.com/repository/maven-snapshots/"
+ );
+ }
+
+ const cookbookContent = readFileSync(join(markdown, "cookbook", "error-handling.md"), "utf8");
+ assert.equal(
+ cookbookContent.match(/\/\/REPOS central,central-snapshots=/g)?.length,
+ cookbookContent.match(/\/\/DEPS com\.github:copilot-sdk-java:1\.0\.15-SNAPSHOT/g)?.length
+ );
+});
+
+test("keeps stable dependency rendering free of snapshot configuration", (t) => {
+ const markdown = fixture(t);
+ prepareSiteVersions("1.0.15", "1.0.15", markdown);
+
+ const gettingStarted = readFileSync(join(markdown, "getting-started.md"), "utf8");
+ assert.doesNotMatch(gettingStarted, /maven-snapshots/);
+ assert.doesNotMatch(gettingStarted, /ARTIFACT_/);
+ const cookbook = readFileSync(join(markdown, "cookbook", "managing-local-files.md"), "utf8");
+ assert.match(cookbook, /copilot-sdk-java:1\.0\.15/);
+});
+
+test("rejects an artifact version from another shared base", (t) => {
+ const markdown = fixture(t);
+ assert.throws(
+ () => prepareSiteVersions("1.0.15-preview.2", "1.0.16-SNAPSHOT", markdown),
+ /site version's base/
+ );
+});
+
+test("passes artifact inputs through the workflow environment and detects previews by version", () => {
+ const workflow = readFileSync(resolve(".github/workflows/deploy-site.yml"), "utf8");
+ const prepareStep = workflow.slice(
+ workflow.indexOf("- name: Prepare site artifact versions"),
+ workflow.indexOf("# 6. Build the Maven Site")
+ );
+ assert.match(prepareStep, /ARTIFACT_VERSION_INPUT: \$\{\{ inputs\.artifact_version \}\}/);
+ assert.doesNotMatch(prepareStep.match(/run: \|([\s\S]*)/)?.[1] ?? "", /inputs\.artifact_version/);
+ assert.match(prepareStep, /if \[\[ "\$\{VERSION\}" == \*-\* \]\]/);
+ assert.doesNotMatch(prepareStep, /inputs\.publish_as_latest/);
+});
diff --git a/src/site/markdown/getting-started.md b/src/site/markdown/getting-started.md
index 0bde2ef50d..6f9705e37e 100644
--- a/src/site/markdown/getting-started.md
+++ b/src/site/markdown/getting-started.md
@@ -29,17 +29,19 @@ copilot --version
## Step 1: Install the SDK
-> If you want to test a _-SNAPSHOT_ version, you may have to clone the project's repository and install the library locally with _mvn install_.
+Preview documentation can use a rolling `-SNAPSHOT` artifact version. Multiple previews of the same base SDK version update that coordinate, so an older preview's documentation directory does not guarantee an exact historical preview build.
### Apache Maven
Add the dependency to your `pom.xml`:
+
+
```xml
com.github
copilot-sdk-java
- ${project.version}
+ ${artifact.version}
```
@@ -47,8 +49,10 @@ Add the dependency to your `pom.xml`:
Add the dependency to your `build.gradle`:
+
+
```groovy
-implementation 'com.github:copilot-sdk-java:${project.version}'
+implementation 'com.github:copilot-sdk-java:${artifact.version}'
```
### JBang (Quick Start)
@@ -56,7 +60,8 @@ implementation 'com.github:copilot-sdk-java:${project.version}'
For the fastest way to try the SDK without setting up a project, use [JBang](https://www.jbang.dev/). Create a file named `HelloCopilot.java` with the following header, and then proceed to Step 2 by appending the proposed content into this same file.
```bash
-//DEPS com.github:copilot-sdk-java:${project.version}
+//ARTIFACT_REPOSITORY
+//DEPS com.github:copilot-sdk-java:${artifact.version}
```
## Step 2: Send Your First Message
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 7819c5f05e..45a4e33bf8 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -15,22 +15,26 @@ Welcome to the documentation for the **GitHub Copilot SDK for Java** — a Java
Add the dependency to your project:
-> **Note:** If this is a `-SNAPSHOT` version, clone the project repository and run `./mvnw install` locally first so the artifact is available in your local Maven cache. Otherwise, the version is available on Maven Central.
+Preview documentation can use a rolling `-SNAPSHOT` artifact version. Multiple previews of the same base SDK version update that coordinate, so an older preview's documentation directory does not guarantee an exact historical preview build.
**Maven:**
+
+
```xml
com.github
copilot-sdk-java
- ${project.version}
+ ${artifact.version}
```
**Gradle:**
+
+
```groovy
-implementation 'com.github:copilot-sdk-java:${project.version}'
+implementation 'com.github:copilot-sdk-java:${artifact.version}'
```
### Quick Example
@@ -86,7 +90,8 @@ You can quickly try the SDK without setting up a full project using [JBang](http
# Create a simple script
cat > hello-copilot.java << 'EOF'
-//DEPS com.github:copilot-sdk-java:${project.version}
+//ARTIFACT_REPOSITORY
+//DEPS com.github:copilot-sdk-java:${artifact.version}
import com.github.copilot.CopilotClient;
import com.github.copilot.generated.AssistantMessageEvent;
import com.github.copilot.generated.SessionIdleEvent;