Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/aw/bootstrap-agentic-campaign.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ When no work items are discovered, dispatch a seeder/scanner worker to discover
**Seeder Worker Contract**:
- MUST accept `campaign_id` and `payload` inputs (standard worker contract)
- MUST create discoverable outputs (issues, PRs, or discussions)
- MUST apply the tracker label: `campaign:{{ .CampaignID }}`
- MUST apply the tracker label: `z_campaign_{{ .CampaignID }}`
- SHOULD limit output count to configured max-items if provided
- SHOULD use deterministic work item keys for idempotency

Expand Down Expand Up @@ -88,7 +88,7 @@ When no work items are discovered, read from the Project board's "{{ .TodoValue
No automatic bootstrap configured. Wait for manual work item creation:

- Work items should be created manually (issues, PRs, or discussions)
- All items MUST have the tracker label: `campaign:{{ .CampaignID }}`
- All items MUST have the tracker label: `z_campaign_{{ .CampaignID }}`
- Items MUST follow the worker output labeling contract
- Once items exist, the orchestrator will discover them normally

Expand Down Expand Up @@ -116,7 +116,7 @@ When dispatching workers during bootstrap, use deterministic selection:
{{ end }}- Key in Title: {{ .OutputLabeling.KeyInTitle }}
{{ if .OutputLabeling.KeyFormat }}- Key Format: `{{ .OutputLabeling.KeyFormat }}`
{{ end }}
- Campaign tracker label applied automatically: `campaign:{{ $.CampaignID }}`
- Campaign tracker label applied automatically: `z_campaign_{{ $.CampaignID }}`

**Idempotency Strategy**: {{ .IdempotencyStrategy }}

Expand Down
6 changes: 3 additions & 3 deletions .github/aw/execute-agentic-campaign-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The following campaign workers are referenced by this campaign:
- Use `workflow_dispatch` as the ONLY trigger (no schedule/push/pull_request)
- Accept `campaign_id` (string) and `payload` (string; JSON) inputs
- Implement idempotency via deterministic work item keys
- Label all created items with `campaign:{{ .CampaignID }}`
- Label all created items with `z_campaign_{{ .CampaignID }}`

---

Expand Down Expand Up @@ -119,12 +119,12 @@ Expected payload structure:

2. **Check for existing work**:
- Search for PRs/issues with `workKey` in title
- Filter by label: `campaign:${campaignId}`
- Filter by label: `z_campaign_${campaignId}`
- If found: Skip or update
- If not: Create new

3. **Label all created items**:
- Apply `campaign:${campaignId}` label
- Apply `z_campaign_${campaignId}` label
- This enables discovery by orchestrator

## Task
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/security-alert-burndown.campaign.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions actions/setup/js/campaign_discovery.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ async function searchByTrackerId(octokit, trackerId, repos, orgs, maxItems, maxP
if (scopeParts.length > 0) {
const scopeQuery = scopeParts.join(" ");
// Check if combined query would exceed GitHub's limit
if (searchQuery.length + scopeQuery.length + 3 > 1000) {
core.warning(`Search query length (${searchQuery.length + scopeQuery.length}) approaches GitHub's ~1024 character limit. Some repos/orgs may be omitted.`);
if (searchQuery.length + scopeQuery.length + 1 > 1000) {
core.warning(`Search query length (${searchQuery.length + scopeQuery.length + 1}) approaches GitHub's ~1024 character limit. Some repos/orgs may be omitted.`);
}
searchQuery = `${searchQuery} (${scopeQuery})`;
searchQuery = `${searchQuery} ${scopeQuery}`;
core.info(`Scoped search to: ${scopeParts.join(", ")}`);
}

Expand Down Expand Up @@ -240,10 +240,10 @@ async function searchByLabel(octokit, label, repos, orgs, maxItems, maxPages, cu
if (scopeParts.length > 0) {
const scopeQuery = scopeParts.join(" ");
// Check if combined query would exceed GitHub's limit
if (searchQuery.length + scopeQuery.length + 3 > 1000) {
core.warning(`Search query length (${searchQuery.length + scopeQuery.length}) approaches GitHub's ~1024 character limit. Some repos/orgs may be omitted.`);
if (searchQuery.length + scopeQuery.length + 1 > 1000) {
core.warning(`Search query length (${searchQuery.length + scopeQuery.length + 1}) approaches GitHub's ~1024 character limit. Some repos/orgs may be omitted.`);
}
searchQuery = `${searchQuery} (${scopeQuery})`;
searchQuery = `${searchQuery} ${scopeQuery}`;
core.info(`Scoped search to: ${scopeParts.join(", ")}`);
}

Expand Down
10 changes: 10 additions & 0 deletions actions/setup/js/campaign_discovery.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ describe("campaign_discovery", () => {
const call = octokit.rest.search.issuesAndPullRequests.mock.calls[0][0];
expect(call.q).toContain('"gh-aw-tracker-id: workflow-1"');
expect(call.q).toContain("org:myorg");
expect(call.q).not.toContain("(");
expect(call.q).not.toContain(")");
});

it("should build query with both repos and orgs", async () => {
Expand All @@ -261,6 +263,8 @@ describe("campaign_discovery", () => {
expect(call.q).toContain('"gh-aw-tracker-id: workflow-1"');
expect(call.q).toContain("repo:owner/repo1");
expect(call.q).toContain("org:myorg");
expect(call.q).not.toContain("(");
expect(call.q).not.toContain(")");
});
});

Expand Down Expand Up @@ -311,6 +315,8 @@ describe("campaign_discovery", () => {
expect(call.q).toContain('label:"campaign:test"');
expect(call.q).toContain("repo:owner/repo1");
expect(call.q).toContain("repo:owner/repo2");
expect(call.q).not.toContain("(");
expect(call.q).not.toContain(")");
});

it("should build org-specific query when orgs provided", async () => {
Expand All @@ -330,6 +336,8 @@ describe("campaign_discovery", () => {
expect(call.q).toContain('label:"campaign:test"');
expect(call.q).toContain("org:myorg");
expect(call.q).toContain("org:anotherorg");
expect(call.q).not.toContain("(");
expect(call.q).not.toContain(")");
});

it("should build combined query when both repos and orgs provided", async () => {
Expand All @@ -349,6 +357,8 @@ describe("campaign_discovery", () => {
expect(call.q).toContain('label:"campaign:test"');
expect(call.q).toContain("repo:owner/repo1");
expect(call.q).toContain("org:myorg");
expect(call.q).not.toContain("(");
expect(call.q).not.toContain(")");
});
});

Expand Down
6 changes: 3 additions & 3 deletions pkg/cli/templates/execute-agentic-campaign-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The following campaign workers are referenced by this campaign:
- Use `workflow_dispatch` as the ONLY trigger (no schedule/push/pull_request)
- Accept `campaign_id` (string) and `payload` (string; JSON) inputs
- Implement idempotency via deterministic work item keys
- Label all created items with `campaign:{{ .CampaignID }}`
- Label all created items with `z_campaign_{{ .CampaignID }}`

---

Expand Down Expand Up @@ -119,12 +119,12 @@ Expected payload structure:

2. **Check for existing work**:
- Search for PRs/issues with `workKey` in title
- Filter by label: `campaign:${campaignId}`
- Filter by label: `z_campaign_${campaignId}`
- If found: Skip or update
- If not: Create new

3. **Label all created items**:
- Apply `campaign:${campaignId}` label
- Apply `z_campaign_${campaignId}` label
- This enables discovery by orchestrator

## Task
Expand Down
Loading