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
27 changes: 24 additions & 3 deletions actions/setup/js/assign_milestone.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
const { getErrorMessage } = require("./error_helpers.cjs");
const { logStagedPreviewInfo } = require("./staged_preview.cjs");
const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs");
const { loadTemporaryIdMapFromResolved, resolveRepoIssueTarget } = require("./temporary_id.cjs");

/** @type {string} Safe output type handled by this module */
const HANDLER_TYPE = "assign_milestone";
Expand Down Expand Up @@ -57,17 +58,37 @@ async function main(config = {}) {

const item = message;

const issueNumber = Number(item.issue_number);
const milestoneNumber = Number(item.milestone_number);
// Convert resolvedTemporaryIds to a normalized Map for resolveRepoIssueTarget
const temporaryIdMap = loadTemporaryIdMapFromResolved(resolvedTemporaryIds);

// Resolve issue_number, which may be a temporary ID (e.g. "aw_abc123") or a plain number
const resolvedIssueTarget = resolveRepoIssueTarget(item.issue_number, temporaryIdMap, context.repo.owner, context.repo.repo);

Comment on lines +64 to 66
if (isNaN(issueNumber) || issueNumber <= 0) {
// If the issue_number is a temporary ID that hasn't been resolved yet, defer processing
if (resolvedIssueTarget.wasTemporaryId && !resolvedIssueTarget.resolved) {
core.info(`Deferring assign_milestone: unresolved temporary ID (${item.issue_number})`);
return {
success: false,
deferred: true,
error: resolvedIssueTarget.errorMessage || `Unresolved temporary ID: ${item.issue_number}`,
};
}

if (resolvedIssueTarget.errorMessage || !resolvedIssueTarget.resolved) {
core.error(`Invalid issue_number: ${item.issue_number}`);
return {
success: false,
error: `Invalid issue_number: ${item.issue_number}`,
};
}

const issueNumber = resolvedIssueTarget.resolved.number;
if (resolvedIssueTarget.wasTemporaryId) {
core.info(`Resolved temporary ID '${item.issue_number}' to issue #${issueNumber}`);
}

const milestoneNumber = Number(item.milestone_number);

if (isNaN(milestoneNumber) || milestoneNumber <= 0) {
core.error(`Invalid milestone_number: ${item.milestone_number}`);
return {
Expand Down
41 changes: 41 additions & 0 deletions actions/setup/js/assign_milestone.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,45 @@ describe("assign_milestone (Handler Factory Architecture)", () => {
expect(result.success).toBe(false);
expect(result.error).toContain("Invalid milestone_number");
});

it("should resolve a temporary ID for issue_number", async () => {
mockGithub.rest.issues.update.mockResolvedValue({});

const message = {
type: "assign_milestone",
issue_number: "aw_abc123",
milestone_number: 5,
};

const resolvedTemporaryIds = {
aw_abc123: { repo: "test-owner/test-repo", number: 42 },
};

const result = await handler(message, resolvedTemporaryIds);

expect(result.success).toBe(true);
expect(result.issue_number).toBe(42);
expect(result.milestone_number).toBe(5);
expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({
owner: "test-owner",
repo: "test-repo",
issue_number: 42,
milestone: 5,
});
});

it("should defer when temporary ID is not yet resolved", async () => {
const message = {
type: "assign_milestone",
issue_number: "aw_pending1",
milestone_number: 5,
};

// No resolved temporary IDs provided
const result = await handler(message, {});

expect(result.success).toBe(false);
expect(result.deferred).toBe(true);
expect(mockGithub.rest.issues.update).not.toHaveBeenCalled();
});
});
2 changes: 1 addition & 1 deletion actions/setup/js/safe_outputs_tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@
"properties": {
"issue_number": {
"type": ["number", "string"],
"description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567)."
"description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567). Can also be a temporary_id (e.g., 'aw_abc123') from a previously created issue in the same workflow run."
},
"milestone_number": {
"type": ["number", "string"],
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/js/safe_outputs_tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@
"number",
"string"
],
"description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567)."
"description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567). Can also be a temporary_id (e.g., 'aw_abc123') from a previously created issue in the same workflow run."
},
"milestone_number": {
"type": [
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/safe_outputs_validation_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ var ValidationConfig = map[string]TypeValidationConfig{
"assign_milestone": {
DefaultMax: 1,
Fields: map[string]FieldValidation{
"issue_number": {IssueOrPRNumber: true},
"issue_number": {IssueNumberOrTemporaryID: true},
"milestone_number": {Required: true, PositiveInteger: true},
"repo": {Type: "string", MaxLength: 256}, // Optional: target repository in format "owner/repo"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
await main(core, context);
- name: Validate COPILOT_GITHUB_TOKEN secret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
await main(core, context);
- name: Validate COPILOT_GITHUB_TOKEN secret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
await main(core, context);
- name: Validate COPILOT_GITHUB_TOKEN secret
Expand Down