Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a53aa3d
Initial plan
Copilot Jan 31, 2026
a481c9f
Initial plan: Unify safe output processing
Copilot Jan 31, 2026
ab845dc
Add unified safe output handler manager with Octokit support
Copilot Jan 31, 2026
19dfb10
Update project handlers to support new signature with temporary IDs
Copilot Jan 31, 2026
ab20d63
Add tests for unified safe output handler manager
Copilot Jan 31, 2026
7a1ba04
Fix code review issues: Update JSDoc and YAML formatting
Copilot Jan 31, 2026
aa23f37
Recompile ci-doctor workflow after YAML formatting fix
Copilot Jan 31, 2026
165be7d
Remove @actions/github dependency - use github object from github-scr…
Copilot Jan 31, 2026
e4a1af3
Unify temporary maps into single map - temp IDs are unique
Copilot Jan 31, 2026
05b2f2d
Add separate Octokit client for project handlers with npm install
Copilot Jan 31, 2026
58e6f63
Pass Octokit client as parameter instead of global.github override
Copilot Jan 31, 2026
92873df
Add clarity comments for conditional project Octokit instantiation
Copilot Jan 31, 2026
0c32c77
Add safe-outputs input flag to guard @actions/github installation
Copilot Jan 31, 2026
5e8d7be
Rename flag to safe-output-projects and auto-enable from compiler
Copilot Jan 31, 2026
56484c2
Fix TypeScript type errors and test exceptions
Copilot Jan 31, 2026
a33831a
Apply review comments: lazy-load @actions/github and extract campaign…
Copilot Jan 31, 2026
3430263
Changes before error encountered
Copilot Jan 31, 2026
8d26b1e
Merge main branch and recompile all workflows
Copilot Jan 31, 2026
64e9b4c
Merge remote-tracking branch 'origin/main' into copilot/unify-safe-ou…
Jan 31, 2026
6593fff
Merge main branch and recompile workflows (iteration 2)
Copilot Jan 31, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/dependabot-burner.lock.yml

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

1,495 changes: 12 additions & 1,483 deletions .github/workflows/functional-pragmatist.lock.yml

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions .github/workflows/functional-pragmatist.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ tools:
edit:
bash:
- "*"
cache:
enabled: true
keys:
- "last_processed_package"
- "processed_packages"

timeout-minutes: 45
strict: true
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/security-alert-burndown.lock.yml

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

1 change: 1 addition & 0 deletions .github/workflows/test-project-url-default.lock.yml

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

5 changes: 5 additions & 0 deletions actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ inputs:
description: 'Destination directory for activation files (default: /opt/gh-aw/actions)'
required: false
default: '/opt/gh-aw/actions'
safe-output-projects:
description: 'Enable safe-output-projects support (installs @actions/github package for project handlers)'
required: false
default: 'false'

outputs:
files-copied:
Expand All @@ -19,6 +23,7 @@ runs:
shell: bash
env:
INPUT_DESTINATION: ${{ inputs.destination }}
INPUT_SAFE_OUTPUT_PROJECTS: ${{ inputs.safe-output-projects }}
run: ${{ github.action_path }}/setup.sh

branding:
Expand Down
46 changes: 46 additions & 0 deletions actions/setup/js/campaign_labels.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// @ts-check

/**
* Campaign Labels Helper
*
* Utility functions for handling campaign labels in safe outputs.
* These functions normalize campaign IDs and retrieve campaign labels from environment variables.
*/

const DEFAULT_AGENTIC_CAMPAIGN_LABEL = "agentic-campaign";

/**
* Normalize campaign IDs to the same label format used by campaign discovery.
* Mirrors actions/setup/js/campaign_discovery.cjs.
* @param {string} campaignId
* @returns {string}
*/
function formatCampaignLabel(campaignId) {
return `z_campaign_${String(campaignId)
.toLowerCase()
.replace(/[_\s]+/g, "-")}`;
}

/**
* Get campaign labels implied by environment variables.
* Returns the generic "agentic-campaign" label and the campaign-specific "z_campaign_<id>" label.
* @returns {{enabled: boolean, labels: string[]}}
*/
function getCampaignLabelsFromEnv() {
const campaignId = String(process.env.GH_AW_CAMPAIGN_ID || "").trim();

if (!campaignId) {
return { enabled: false, labels: [] };
}

const specificLabel = formatCampaignLabel(campaignId);
return {
enabled: true,
labels: [DEFAULT_AGENTIC_CAMPAIGN_LABEL, specificLabel],
};
}

module.exports = {
formatCampaignLabel,
getCampaignLabelsFromEnv,
};
16 changes: 13 additions & 3 deletions actions/setup/js/copy_project.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,23 @@ async function copyProject(output) {
* @param {number} [config.max] - Maximum number of copy_project items to process
* @param {string} [config.source_project] - Default source project URL
* @param {string} [config.target_owner] - Default target owner
* @param {Object} githubClient - GitHub client (Octokit instance) to use for API calls
* @returns {Promise<Function>} Message handler function
*/
async function main(config = {}) {
async function main(config = {}, githubClient = null) {
// Extract configuration
const maxCount = config.max || 10;
const defaultSourceProject = config.source_project || "";
const defaultTargetOwner = config.target_owner || "";

// Use the provided github client, or fall back to the global github object
// @ts-ignore - global.github is set by setupGlobals() from github-script context
const github = githubClient || global.github;

if (!github) {
throw new Error("GitHub client is required but not provided. Either pass a github client to main() or ensure global.github is set by github-script action.");
}

core.info(`Max count: ${maxCount}`);
if (defaultSourceProject) {
core.info(`Default source project: ${defaultSourceProject}`);
Expand All @@ -281,10 +290,11 @@ async function main(config = {}) {
/**
* Message handler function that processes a single copy_project message
* @param {Object} message - The copy_project message to process
* @param {Object} resolvedTemporaryIds - Map of temporary IDs (unused for copy_project)
* @param {Map<string, {repo?: string, number?: number, projectUrl?: string}>} temporaryIdMap - Unified map of temporary IDs
* @param {Object} resolvedTemporaryIds - Plain object version of temporaryIdMap for backward compatibility
* @returns {Promise<Object>} Result with success/error status and project details
*/
return async function handleCopyProject(message, resolvedTemporaryIds) {
return async function handleCopyProject(message, temporaryIdMap, resolvedTemporaryIds = {}) {
// Check max limit
if (processedCount >= maxCount) {
core.warning(`Skipping copy_project: max count of ${maxCount} reached`);
Expand Down
18 changes: 13 additions & 5 deletions actions/setup/js/create_project.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -284,17 +284,24 @@ async function createProjectView(projectUrl, viewConfig) {
/**
* Main entry point - handler factory that returns a message handler function
* @param {Object} config - Handler configuration
* @param {Object} githubClient - GitHub client (Octokit instance) to use for API calls
* @returns {Promise<Function>} Message handler function
*/
async function main(config = {}) {
async function main(config = {}, githubClient = null) {
// Extract configuration
const defaultTargetOwner = config.target_owner || "";
const maxCount = config.max || 1;
const titlePrefix = config.title_prefix || "Campaign";
const configuredViews = Array.isArray(config.views) ? config.views : [];

// The github object is already authenticated with the custom token via the
// github-token parameter set on the actions/github-script action
// Use the provided github client, or fall back to the global github object
// The global github object is available when running via github-script action
// @ts-ignore - global.github is set by setupGlobals() from github-script context
const github = githubClient || global.github;

if (!github) {
throw new Error("GitHub client is required but not provided. Either pass a github client to main() or ensure global.github is set by github-script action.");
}

if (defaultTargetOwner) {
core.info(`Default target owner: ${defaultTargetOwner}`);
Expand All @@ -313,10 +320,11 @@ async function main(config = {}) {
/**
* Message handler function that processes a single create_project message
* @param {Object} message - The create_project message to process
* @param {Object} resolvedTemporaryIds - Map of temporary IDs (unused for create_project)
* @param {Map<string, {repo?: string, number?: number, projectUrl?: string}>} temporaryIdMap - Unified map of temporary IDs
* @param {Object} resolvedTemporaryIds - Plain object version of temporaryIdMap for backward compatibility
* @returns {Promise<Object>} Result with success/error status
*/
return async function handleCreateProject(message, resolvedTemporaryIds) {
return async function handleCreateProject(message, temporaryIdMap, resolvedTemporaryIds = {}) {
// Check max limit
if (processedCount >= maxCount) {
core.warning(`Skipping create_project: max count of ${maxCount} reached`);
Expand Down
19 changes: 15 additions & 4 deletions actions/setup/js/create_project_status_update.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,21 @@ function formatDate(date) {
/**
* Main handler factory for create_project_status_update
* Returns a message handler function that processes individual create_project_status_update messages
* @type {HandlerFactoryFunction}
* @param {Object} config - Handler configuration
* @param {Object} githubClient - GitHub client (Octokit instance) to use for API calls
* @returns {Promise<Function>} Message handler function
*/
async function main(config = {}) {
async function main(config = {}, githubClient = null) {
const maxCount = config.max || 10;

// Use the provided github client, or fall back to the global github object
// @ts-ignore - global.github is set by setupGlobals() from github-script context
const github = githubClient || global.github;

if (!github) {
throw new Error("GitHub client is required but not provided. Either pass a github client to main() or ensure global.github is set by github-script action.");
}

core.info(`Max count: ${maxCount}`);

// Track how many items we've processed for max limit
Expand All @@ -281,10 +291,11 @@ async function main(config = {}) {
/**
* Message handler function that processes a single create_project_status_update message
* @param {Object} message - The create_project_status_update message to process
* @param {Object} resolvedTemporaryIds - Map of temporary IDs to {repo, number}
* @param {Map<string, {repo?: string, number?: number, projectUrl?: string}>} temporaryIdMap - Unified map of temporary IDs
* @param {Object} resolvedTemporaryIds - Plain object version of temporaryIdMap for backward compatibility
* @returns {Promise<Object>} Result with success/error status and status update details
*/
return async function handleCreateProjectStatusUpdate(message, resolvedTemporaryIds) {
return async function handleCreateProjectStatusUpdate(message, temporaryIdMap, resolvedTemporaryIds = {}) {
// Check if we've hit the max limit
if (processedCount >= maxCount) {
core.warning(`Skipping create-project-status-update: max count of ${maxCount} reached`);
Expand Down
Loading
Loading