Skip to content

feat(v4): add core-next & cli-next packages with integration/E2E test…#15663

Draft
Alive-Fish wants to merge 48 commits intodevfrom
zhiyou/v4
Draft

feat(v4): add core-next & cli-next packages with integration/E2E test…#15663
Alive-Fish wants to merge 48 commits intodevfrom
zhiyou/v4

Conversation

@Alive-Fish
Copy link
Copy Markdown
Contributor

…s and CI workflows

  • Add core-next engine: operations, drivers, DA manifest, templates, lifecycle
  • Add cli-next CLI: Commander.js commands, action handlers, telemetry, auth
  • Add integration tests: 24 core-next + 62 cli-next
  • Add E2E tests: cli-syntax verification with scaffold tests
  • Add CI workflow (ci-next.yml): build, lint, format, unit+integration tests
  • Add E2E workflow (e2e-test-next.yml): matrix test execution with failure summary
  • Add instruction files, skills, and plans for v4 development

…s and CI workflows

- Add core-next engine: operations, drivers, DA manifest, templates, lifecycle
- Add cli-next CLI: Commander.js commands, action handlers, telemetry, auth
- Add integration tests: 24 core-next + 62 cli-next
- Add E2E tests: cli-syntax verification with scaffold tests
- Add CI workflow (ci-next.yml): build, lint, format, unit+integration tests
- Add E2E workflow (e2e-test-next.yml): matrix test execution with failure summary
- Add instruction files, skills, and plans for v4 development
- Add esbuild.mjs config: single-file CJS bundle, node18 target, keepNames
- Add bundle/package/prepack scripts to package.json
- Lazy-load applicationinsights (require inside init, not top-level import)
- Defer registerBuiltinDrivers() from startup to wrapHandlerWithContext()
- Update cli.instructions.md and codebase.instructions.md with bundling docs

Before: node cli.js --help took ~18.5s (unbundled tsc output)
After:  node cli.js --help takes ~490ms (esbuild bundle, 2.2MB prod)
…ame conflicts

core-next: @microsoft/teamsfx-core -> @microsoft/teamsfx-core-next
cli-next: @microsoft/m365agentstoolkit-cli -> @microsoft/m365agentstoolkit-cli-next

Both packages shared names with their v3 counterparts (fx-core, cli),
causing pnpm install to fail during CI setup.
- dev-test-next: fix .tests.ts -> .test.ts extensions, add 3 new E2E test suites
  (mcp-scaffold, auth-commands, add-capability), remove format-check references,
  update verification checklist
- dev-workflow: reference lint-format skill in Phase 5
- lint-format: new skill documenting ESLint+Prettier pipeline architecture
lifecycle.test.ts dynamically generates tests from templateRegistry.list(),
but the registry is empty until registerBuiltinTemplates() is called.
Without this call, Mocha sees 0 test cases and passes vacuously in 4s.

Also adds a guard that throws if the registry is still empty after
initialization, preventing silent 0-test passes in the future.
Instead of running all 43 templates sequentially in one lifecycle.test.ts
job (which would take hours), expand each template into its own matrix
entry: lifecycle.test.ts::da/basic, lifecycle.test.ts::bot/echo, etc.

The setup job reads templateRegistry to generate entries. The run step
parses the :: separator and passes --grep to Mocha so each job only
runs the matching template's language variants.
In CI, the test context was using the interactive CLI auth (createTokenProvider)
which opens browser popups for MSAL login — this hangs indefinitely on headless
CI runners.

Add ciTokenProvider.ts with:
- M365LoginCI: uses acquireTokenByUsernamePassword (MSAL ROPC flow)
- AzureLoginCIUserPassword: uses UsernamePasswordCredential from @azure/identity

testContext.ts now checks isCIMode() (CI_ENABLED=true) and uses the CI
provider instead of the interactive one.
azure/login@v1 with OIDC (federated credentials) exports AZURE_TENANT_ID
and AZURE_SUBSCRIPTION_ID to GITHUB_ENV, overriding the test-user values
set at job level. This caused all 43 lifecycle tests to authenticate the
test user against the DEVOPS tenant, which fails immediately.

Add 'Restore test env vars' steps right after azure/login in both the
setup and execute-case jobs to write the correct test secrets back to
GITHUB_ENV.
…alidation, and optimization

- Add 8 source files: types, constants, parser, utils, validator, filter, optimizer, index
- Add RealSpecParserAdapter implementing SpecParserAdapter interface
- Wire createSpecParserAdapter factory to return RealSpecParserAdapter
- Export specParser module from core-next index
- Add dependencies: swagger-parser, swagger2openapi, openapi-types
// Copy path-level properties (servers, parameters, etc.) but not operations
newPaths[path] = { ...unresolvedSpec.paths![path] };
for (const m of HTTPMethodsConst.AllOperationMethods) {
delete (newPaths[path] as Record<string, unknown>)[m];
}
}

(newPaths[path] as Record<string, unknown>)[methodName] = (
Three root causes found and fixed:

1. C# scaffold EISDIR crash: Missing Mustache variables (NewProjectTypeName,
   NewProjectTypeExt, SolutionName, PlaceProjectFileInSolutionDir) in
   getTemplateReplaceMap caused C# template file paths to collapse to empty
   strings, resulting in EISDIR when writing to the project directory path.
   Fix: Add the missing variables to replaceMap.ts matching fx-core defaults.

2. Provision empty AZURE_RESOURCE_GROUP_NAME: Templates scaffold .env.dev
   with AZURE_RESOURCE_GROUP_NAME= (empty). The test checked for key presence
   (not empty value), so it never injected the actual RG name. Additionally,
   provisionOp's analyzeSteps treated empty strings as 'resolved', skipping
   ensureResourceGroup(). Fix: Use upsertEnvVar in the test to replace
   empty values, and check for empty strings in provisionOp.

3. Driver projectPath missing: teamsApp/zipAppPackage requires projectPath
   but YAML templates don't include it in the 'with' block. The lifecycle
   executor now auto-injects ctx.projectPath when the config lacks it.

Also includes:
- UUID validation for cached tenant IDs (cacheAccess.ts)
- Stale cache cleanup in E2E setup.ts
- Unit test fix for provisionOp portal link test
- executor.ts: temporarily sync envMap into process.env before each driver
  call so drivers loading external files (ARM params, AAD manifests) can
  resolve ${{VAR}} placeholders; cleaned up in finally block
- createDriver.ts: detect AtkError plain objects in wrapUnexpectedError()
  and return them directly instead of wrapping with String() which produced
  [object Object]
- aadApp/update.ts: resolve env placeholders in AAD manifest template
  before JSON parsing; return UnresolvedManifestVars error if any remain
- openApi.ts: mark 3 OpenAPI templates (da/api-plugin-from-spec,
  ai-agent/rag-from-spec, me/from-spec) as testable: false since they
  require interactive apiSpecPath input
- declarativeAgent.ts: mark da/graph-connector as testable: false since
  its template artifact lacks appPackage/manifest.json
- lifecycle.test.ts: always create env/ dir and .env.dev with required
  vars; detect lifecycle sections in YAML before provision/deploy to
  gracefully skip templates without those phases
- cli-syntax.test.ts: replace nonexistent template names (tab dashboard,
  bot notification-express) with real registry entries (tab basic, cea basic)
- fx-core.instructions.md: document executor process.env sync, createDriver
  AtkError handling, aadApp/update env resolution
- features.instructions.md: document testable flag and 4 testable:false templates
- dev-test-next SKILL.md: add lifecycle-aware, env bootstrapping, and testable
  filtering design decisions
- lifecycle-e2e plan: add 2026-04-13 log with 8 root cause fixes
…rivers and YAML

Drivers output UPPER_CASE keys (e.g. TEAMS_APP_ID) while YAML
writeToEnvironmentFile uses camelCase keys (e.g. teamsAppId).
The executor now checks both conventions so env vars flow correctly
between lifecycle steps.
- Fix scaffold lang mismatch for da/typespec, da/mcp-local

- Check Azure-requiring drivers instead of section presence

- Remove forced teamsApp validator without provision

- Fix noSpuriousErrors rule to check per-operation

- Reorder phases: detect lifecycle before RG creation
- render.ts: Fix Mustache eating ${{VAR}} placeholders by using NUL-byte
  sentinels instead of literal {{VAR}} text tokens. Prevents re-parsing
  on cache miss when templates contain section tags.
- createDriver.ts: Add missing success attribute and fix duration
  metric name in driver-end telemetry event.
- extendToM365.ts: Handle case-insensitive scope enum values (personal
  vs Personal) with normalizeAppScope() helper.
- declarativeAgent.ts: Mark da/typespec as testable: false until
  typeSpec/compile driver is ported from fx-core.
- validateManifest: resolve manifestPath relative to ctx.projectPath (fixes
  ENOENT for csharp templates where cwd != projectPath)
- engineAgent: add csharp template name override for function-calling
  (csharp.zip uses 'custom-copilot-weather-agent' not 'weather-agent')
- declarativeAgent: mark da/api-plugin-oauth, da/mcp-remote, da/mcp-local
  as testable:false (infra/env prerequisites not available in CI)
- lifecycle test: pass llmService='azure-openai' so Mustache conditionals
  for LLM client code render correctly (fixes 4 ts npm build failures)
- lifecycle test: add collectUnresolvedParameterVars() to pre-populate
  dummy env vars for unresolved parameters.json placeholders (fixes
  rag-ai-search, bearer, teams-collaborator provision failures)
… fallback

- Make baseUrl optional in oauth/register driver schema (matches fx-core behavior)
- Add apiSpecPath support: extract server domains from OpenAPI spec when baseUrl absent
- Re-enable da/api-plugin-oauth as testable (remove testable: false)
- Improve extendToM365 error handling: surface Axios response body in error detail
- Add unit tests for apiSpecPath domain extraction and missing baseUrl error
…ster and apiKey/register

- oauth/register: output 'configurationId' instead of 'OAUTH2_CONFIGURATION_ID'
  so executor's outputs[yamlKey] lookup matches the writeToEnvironmentFile mapping
- apiKey/register: output 'registrationId' instead of 'API_KEY_REGISTRATION_ID'
  for the same reason
- The executor maps outputs[yamlKey] ?? outputs[envVarName]; these drivers'
  hardcoded keys matched neither side, silently dropping env vars
…dApp/update

- oauth/register: output applicationIdUri from TDP response's resourceIdentifierUri
  for MicrosoftEntra identity provider (maps to AADAUTHCODE_APPLICATION_ID_URI)
- aadApp/update: auto-generate AAD_APP_ACCESS_AS_USER_PERMISSION_ID UUID when
  the AAD manifest references it but no value exists in the environment
- aadApp/update: include generated permission ID in driver outputs so the
  executor persists it to envMap/.env for subsequent runs
…or reporting

- lifecycle.test.ts: only add teamsApp validator when YAML contains
  teamsApp/create, not for all templates with a provision lifecycle
  (connector/graph has provision but no teamsApp/create, so TEAMS_APP_ID
  is never set, causing validate to fail and trigger a flaky retry)
- AzureArmClient: include armErr.details in DeployArmError message so CI
  logs show which specific resource(s) failed during ARM deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants