Skip to content
Open
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
120 changes: 118 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,15 @@ iloom supports multiple issue tracking providers to fit your team's workflow.
| **Linear** | `il init` | Requires API token. Supports full read/write on Linear issues. |
| **Jira** | Configure in `.iloom/settings.json` | Atlassian Cloud. Requires API token. See [Jira Setup](#jira-setup) below. |

### Version Control Providers

Choose which platform hosts your pull requests and code reviews.

| **Provider** | **Setup** | **Notes** |
|--------------|-----------|-----------|
| **GitHub** | `gh auth login` | Default. Integrated with GitHub Issues. |
| **BitBucket** | Configure in `.iloom/settings.json` | Atlassian Cloud. Requires API token. See [BitBucket Setup](#bitbucket-setup) below. |

### Jira Setup

To use Jira as your issue tracker, add this configuration:
Expand Down Expand Up @@ -495,14 +504,122 @@ To use Jira as your issue tracker, add this configuration:
- `doneStatuses`: (Optional) Status names to exclude from `il issues` lists (default: `["Done"]`). Set to match your Jira workflow, e.g., `["Done", "Closed", "Verified"]`
- `transitionMappings`: (Optional) Map iloom states to your Jira workflow transition names

### BitBucket Setup

To use BitBucket for pull requests, add this configuration:

**.iloom/settings.json (Committed)**
```json
{
"versionControl": {
"provider": "bitbucket",
"bitbucket": {
"username": "your-bitbucket-username",
"workspace": "your-workspace",
"repoSlug": "your-repo"
}
},
"mergeBehavior": {
"mode": "bitbucket-pr"
}
}
```

**.iloom/settings.local.json (Gitignored - Never commit this file)**
```json
{
"versionControl": {
"bitbucket": {
"apiToken": "your-bitbucket-api-token"
}
}
}
```

**Generate a BitBucket API Token:**
1. Visit https://bitbucket.org/account/settings/app-passwords/
2. Click "Create API token" (Note: App passwords were deprecated September 2025)
3. Grant permissions: `repository:read`, `repository:write`, `pullrequest:read`, `pullrequest:write`
4. Copy the token to `.iloom/settings.local.json`

**Configuration Options:**
- `username`: Your BitBucket username
- `apiToken`: API token (store in settings.local.json only!)
- `workspace`: (Optional) BitBucket workspace, auto-detected from git remote if not provided
- `repoSlug`: (Optional) Repository slug, auto-detected from git remote if not provided
- `reviewers`: (Optional) Array of BitBucket usernames to automatically add as PR reviewers. Usernames are resolved to BitBucket account IDs at PR creation time. Unresolved usernames are logged as warnings but don't block PR creation.

**Example with Reviewers:**
```json
{
"versionControl": {
"provider": "bitbucket",
"bitbucket": {
"username": "your-bitbucket-username",
"reviewers": [
"alice.jones",
"bob.smith"
]
}
},
"mergeBehavior": {
"mode": "bitbucket-pr"
}
}
```

### Jira + BitBucket Together

Use Jira for issues and BitBucket for pull requests:

**.iloom/settings.json**
```json
{
"issueManagement": {
"provider": "jira",
"jira": {
"host": "https://yourcompany.atlassian.net",
"username": "your.email@company.com",
"projectKey": "PROJ"
}
},
"versionControl": {
"provider": "bitbucket",
"bitbucket": {
"username": "your-bitbucket-username"
}
},
"mergeBehavior": {
"mode": "bitbucket-pr"
}
}
```

**.iloom/settings.local.json**
```json
{
"issueManagement": {
"jira": {
"apiToken": "your-jira-api-token"
}
},
"versionControl": {
"bitbucket": {
"apiToken": "your-bitbucket-api-token"
}
}
}
```


### IDE Support
iloom creates isolated workspace settings for your editor. Color synchronization (visual context) only works best VS Code-based editors.

* **Supported:** VS Code, Cursor, Windsurf, Antigravity, WebStorm, IntelliJ, Sublime Text.

* **Config:** Set your preference via `il init` or `il start --set ide.type=cursor`.


### Git Operation Settings

Configure git operation timeouts for projects with long-running pre-commit hooks.
Expand All @@ -522,7 +639,6 @@ Configure git operation timeouts for projects with long-running pre-commit hooks

**When to increase:** If you see timeout errors during `il commit` or `il finish`, your pre-commit hooks are taking longer than the default 60 seconds. Set a higher value based on your typical hook duration.


Advanced Features
-----------------

Expand Down
88 changes: 88 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ program
.option('-n, --dry-run', 'Preview actions without executing')
.option('--pr <number>', 'Treat input as PR number', parseFloat)
.option('--skip-build', 'Skip post-merge build verification')
.option('--skip-to-pr', 'Skip rebase/validation/commit, go directly to PR creation (debug)')
.option('--no-browser', 'Skip opening PR in browser (github-pr mode only)')
.option('--cleanup', 'Clean up worktree after finishing (default in local mode)')
.option('--no-cleanup', 'Keep worktree after finishing')
Expand Down Expand Up @@ -2082,6 +2083,93 @@ program
process.exit(0)
})

// Debug commands - only registered when debug mode is enabled
if (process.env.ILOOM_DEBUG === 'true') {
const debugCommand = program
.command('debug')
.description('Debug tools (only available in debug mode)')

const bitbucketDebugCommand = debugCommand
.command('bitbucket')
.description('BitBucket debug tools')

bitbucketDebugCommand
.command('resolve-reviewer-ids')
.description('Resolve configured reviewer usernames to BitBucket account IDs')
.action(async () => {
try {
const settingsManager = new SettingsManager()
const settings = await settingsManager.loadSettings()

const bitbucketConfig = settings.versionControl?.bitbucket
if (!bitbucketConfig) {
logger.error('BitBucket configuration not found in settings')
logger.info('Configure versionControl.bitbucket in .iloom/settings.json')
process.exit(1)
}

if (!bitbucketConfig.username) {
logger.error('BitBucket username not configured')
logger.info('Configure versionControl.bitbucket.username in .iloom/settings.json')
process.exit(1)
}

if (!bitbucketConfig.apiToken) {
logger.error('BitBucket API token not configured')
logger.info('Configure versionControl.bitbucket.apiToken in .iloom/settings.local.json')
process.exit(1)
}

const reviewers = bitbucketConfig.reviewers ?? []
if (reviewers.length === 0) {
logger.warn('No reviewers configured in settings')
logger.info('Configure versionControl.bitbucket.reviewers in .iloom/settings.json')
console.log(JSON.stringify({}, null, 2))
process.exit(0)
}

// Get workspace from config or auto-detect from git remote
let workspace = bitbucketConfig.workspace
if (!workspace) {
const { parseGitRemotes } = await import('./utils/remote.js')
const remotes = await parseGitRemotes()
const bitbucketRemote = remotes.find(r => r.url.includes('bitbucket.org'))
if (!bitbucketRemote) {
logger.error('Could not auto-detect BitBucket workspace from git remote')
logger.info('Configure versionControl.bitbucket.workspace in .iloom/settings.json')
process.exit(1)
}
workspace = bitbucketRemote.owner
}

// At this point workspace is guaranteed to be a string (either from config or auto-detected)
const resolvedWorkspace = workspace

// Create BitBucket API client and resolve reviewer IDs
const { BitBucketApiClient } = await import('./lib/providers/bitbucket/BitBucketApiClient.js')
const apiClient = new BitBucketApiClient({
username: bitbucketConfig.username,
apiToken: bitbucketConfig.apiToken,
workspace: resolvedWorkspace,
})

const resolvedMap = await apiClient.findUsersByUsername(resolvedWorkspace, reviewers)

// Convert Map to plain object for JSON output
const result: Record<string, string> = {}
for (const [username, accountId] of resolvedMap) {
result[username] = accountId
}

console.log(JSON.stringify(result, null, 2))
process.exit(0)
} catch (error) {
logger.error(`Failed to resolve reviewer IDs: ${error instanceof Error ? error.message : 'Unknown error'}`)
process.exit(1)
}
})
}

// Parse CLI arguments (only when run directly, not when imported for testing)
// Resolve symlinks to handle npm link and global installs
const isRunDirectly = process.argv[1] && ((): boolean => {
Expand Down
Loading