Skip to content

feat(asana): add Asana project management API emulator#4

Merged
amondnet merged 5 commits into
mainfrom
amondnet/minsu-lee/asana
Jun 8, 2026
Merged

feat(asana): add Asana project management API emulator#4
amondnet merged 5 commits into
mainfrom
amondnet/minsu-lee/asana

Conversation

@amondnet

@amondnet amondnet commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports the Asana emulator from the amondnet/minsu-lee/asana branch, adapted to this repo's conventions. Provides stateful emulation of the core Asana REST API v1.0 resources.

  • New package: @pleaseai/emulate-asana (packages/asana)
  • Coverage: users, workspaces, teams, projects, sections, tasks, tags, stories, webhooks
  • Registry: registered in the emulate service registry (default port 4005) with seed config support

Convention alignment (changes from the original)

The original lived under packages/@emulators/asana and used pnpm + vitest. It was adapted to fit this repo's structure.

Area Change
Location / name packages/asana, @pleaseai/emulate-asana
Tests vitest → bun:test (API-compatible, import-only change)
hono dependency Hono/Context/ContentfulStatusCode re-exported from @emulators/core instead of a direct hono dependency (matches the firebase package)
Config added tsconfig.json, tsup.config.ts, package.json (bun test, tsgo)
Lint style single quotes, no semicolons, expanded single-line if blocks
Dead code removed the unused webhooks param in tasks.ts

Verification

  • ✅ 38 asana package tests pass + 7 emulate integration tests pass
  • ✅ Full type-check / build / lint clean (13 tasks)
  • ✅ E2E smoke: started with --service asana --port 4005 → seeded workspace returned correctly, auth middleware works as expected

Port the Asana emulator from the amondnet/minsu-lee/asana branch, adapted
to this repo's conventions: package @pleaseai/emulate-asana, bun test,
tsgo type-check, @emulators/core ^0.6.0 (Hono/Context imported from core
instead of a direct hono dependency), and the repo lint style.

Covers users, workspaces, teams, projects, sections, tasks, tags,
stories, and webhooks over the Asana REST API v1.0. Registered in the
emulate service registry (default port 4005) with seed config support.
@codacy-production

codacy-production Bot commented Jun 8, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 80 high

Alerts:
⚠ 80 issues (≤ 0 issues of at least minor severity)

Results:
80 new issues

Category Results
BestPractice 38 high
ErrorProne 41 high
Security 1 high

View in Codacy

🟢 Metrics 561 complexity · 108 duplication

Metric Results
Complexity 561
Duplication 108

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

@amondnet

amondnet commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

The Asana API emulator successfully implements the core stateful CRUD operations and seeding capabilities required by the specification. However, the current implementation is not up to repository standards according to Codacy, primarily due to 74 new issues and 108 code clones.

Critical logic gaps exist in packages/asana/src/routes/tasks.ts and projects.ts, where mandatory API filters are not enforced, and the 'me' keyword for assignees is not resolved to a valid GID. Additionally, the taskRoutes function has reached a complexity level (172) that makes it a high-risk file for future maintenance. These structural and validation issues should be addressed before merging to ensure the emulator behaves consistently with the real Asana API.

About this PR

  • There is a systemic pattern of boilerplate duplication across all route handlers, particularly regarding fetching entities by GID and returning 404 responses. This has resulted in over 100 detected clones. Implementing a middleware or a higher-order helper function for entity resolution would significantly improve maintainability.

Test suggestions

  • Found recommended test scenario: GET /users/me returns authenticated user details and workspace list
  • Found recommended test scenario: POST /projects creates a project with required workspace and name validation
  • Found recommended test scenario: GET /projects/:gid/task_counts returns computed task metrics
  • Found recommended test scenario: POST /tasks creates a task and supports project/membership inference
  • Found recommended test scenario: Task relationship management: add/remove projects, tags, and dependencies
  • Found recommended test scenario: Subtasks: creating and listing children of a parent task
  • Found recommended test scenario: Stories: adding comments to tasks and verifying editable flags
  • Found recommended test scenario: Webhooks: standard CRUD operations (Create, Read, Update, Delete)
  • Found recommended test scenario: Seeder: Verify all resource types (workspaces, projects, teams, tasks, etc.) populate from config

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread packages/asana/src/routes/projects.ts
Comment thread packages/asana/src/routes/tasks.ts
Comment thread packages/asana/src/routes/tasks.ts Outdated
Comment thread packages/asana/src/routes/tasks.ts Outdated
Comment thread packages/asana/src/routes/tasks.ts Outdated
Comment thread packages/asana/src/routes/tasks.ts
} from '../helpers.js'
import { getAsanaStore } from '../store.js'

export function taskRoutes({ app, store, baseUrl }: RouteContext): void {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

Suggestion: The taskRoutes function is overly complex. Refactor this by extracting the logic for each route (GET, POST, PUT, DELETE, etc.) into separate handler functions or a dedicated controller class. This will reduce the file's cognitive load and improve testability.

Try running the following prompt in your IDE agent:

Refactor the taskRoutes function in packages/asana/src/routes/tasks.ts by extracting every anonymous route handler into its own named function. Ensure the store and context are passed correctly to these handlers.

See Complexity in Codacy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[claude] @codacy-production ⏭️ Skipped for now — every route file in this repo (projects, sections, tags, teams, …) uses the same inline-handler structure, so refactoring only tasks.ts would break that consistency. Worth revisiting repo-wide as a separate change rather than in this PR.

it('GET /users/me returns authenticated user', async () => {
const res = await app.request(`${base}/api/1.0/users/me`, { headers: authHeaders() })
expect(res.status).toBe(200)
const body = await res.json() as any

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Suggestion: The use of as any when parsing JSON responses hides the structure of the emulated API data. Use unknown with a type guard or define a generic interface for Asana API responses to ensure the tests remain robust against internal entity changes.

See Issue in Codacy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[claude] @codacy-production ⏭️ Skipped — as any for parsed JSON is used pervasively across this test file; introducing a typed response helper is a reasonable follow-up but out of scope for this PR.

Comment thread packages/asana/src/routes/projects.ts Outdated
@cubic-dev-ai

cubic-dev-ai Bot commented Jun 8, 2026

Copy link
Copy Markdown

@cubic-dev-ai review

@amondnet I have started the AI code review. It will take a few minutes to complete.

@amondnet amondnet self-assigned this Jun 8, 2026
- GET /projects: require workspace or team, 404 on unknown workspace/team
- GET /tasks: require a workspace/project/section filter, 404 on unknown project
- POST /tasks: validate referenced projects/sections/parent (404 if missing)
- POST /tasks: resolve the 'me' assignee keyword to the authenticated user
- POST /tasks: set completed_at when a task is created already completed
- tasks list: use optional chaining instead of a non-null assertion
- projects: cast html_notes to a nullable type before the ?? default

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/asana/src/routes/tasks.ts Outdated
amondnet added 3 commits June 8, 2026 19:25
A task membership could reference a section belonging to a different
project, producing inconsistent project/section links. Validate that the
section's project matches the membership project, returning 400 otherwise.
Add tests for the request-validation and resource-existence checks
introduced during review (GET/POST 400/404 paths, cross-project section
rejection, 'me' assignee resolution, completed_at on create) plus the
previously untested addFollowers/removeFollowers handlers, project PUT
field updates, and milestone task_counts. Raises new-code coverage above
the 80% quality gate.
# Conflicts:
#	README.md
#	packages/emulate/package.json
#	packages/emulate/src/registry.ts
@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

@amondnet amondnet merged commit cfde302 into main Jun 8, 2026
4 of 5 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 8, 2026
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.

1 participant