Claude Skill

migrate-to-teamcity

Migrating CI/CD pipelines to TeamCity. Use when the user wants to migrate, convert, or switch to TeamCity from GitHub Actions (.github/workflows/) or Bamboo (bamboo-specs/*.yml), even if they only say "move our CI". Other CI systems (GitLab, Jenkins, CircleCI, Azure DevOps, Travi

LLM Mart · 0 points · 6 views 33 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download jetbrains-teamcity-cli-skills_migrate-to-teamcity-ac6c1fd.zip · 11 KB
Part of jetbrains/teamcity-cli — 2 skills

Install

skills CLI npx skills add https://github.com/JetBrains/teamcity-cli/tree/main/skills/migrate-to-teamcity
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install jetbrains-teamcity-cli@llmmart
Git git clone https://github.com/JetBrains/teamcity-cli.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole jetbrains/teamcity-cli collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Migrate to TeamCity

Quick Start

teamcity migrate                    # detect + convert + write .tc.yml files
teamcity migrate --dry-run --json   # preview as structured JSON
teamcity pipeline validate f.tc.yml # schema check
teamcity project vcs create --url <repo-url> --auth anonymous -p ProjectId  # create VCS root first
teamcity pipeline create name -p ProjectId -f f.tc.yml --vcs-root <VcsRootId>
teamcity run start PipelineId --watch

Run teamcity migrate from the repo root -- detection scans .github/workflows/ and bamboo-specs/ relative to the current directory.

Reading the report

  • Needs review -- problems inside the generated YAML: TODO stubs, dropped steps, reusable-workflow placeholders. Fix these in the file before creating the pipeline.
  • Manual setup needed -- work the converter cannot do. Sort each item onto one of two sides: YAML edits (secrets, matrix expansion, expression runs-on, container:/services:) go before pipeline create; server-side configuration (connections, if:-derived branch filters, triggers, notifications) comes after. The checklist below orders them.
  • Exit code 1 means at least one source failed to convert or one generated file failed schema validation -- files that converted cleanly are still written. Read the per-file ✓/⚠/✗ lines instead of treating exit 1 as total failure.
  • --json prints {"sources": [...], "results": [...]} to stdout; each result carries outputFile, yaml, needsReview, manualSetup, and validationError.

Gotchas

  • Always type: script for ./gradlew and ./mvnw. TC's type: gradle/type: maven runners use the agent's version, not the project's. This causes real build failures.
  • Schema valid does not mean pipeline works. Migration is not done until builds pass.
  • Private repos: use a GitHub App connection, not a PAT. Start with teamcity project connection create github-app -p <project> -- its output prints the authorize, App-install, and vcs create follow-up commands. That flow opens a browser; in headless runs pass existing App credentials (--no-manifest --app-id <id> --client-id <id> --private-key-file <pem> --stdin, client secret piped to stdin) or use SSH deploy keys (teamcity project ssh upload with a git@github.com: URL). Public repos: --auth anonymous.
  • Secrets, triggers, and branch filters are always manual. The converter flags them but cannot create them -- the checklist below covers each.
  • VCS root must exist before pipeline create. teamcity pipeline create takes --vcs-root <id>, not a URL. Create it first with teamcity project vcs create.
  • Default branch defaults to main. Pass --branch refs/heads/master to teamcity project vcs create if the repo uses master.
  • Unknown actions/tasks become stubs. Read the action's source, write an equivalent shell script. Most actions are thin CLI wrappers. See mappings.

Workflow

Goal: get all pipeline jobs green on the TC server, not just generate valid YAML.

Copy this checklist and check off items as you complete them:

Migration progress:
- [ ] Convert: run `teamcity migrate` from the repo root
- [ ] Fix every "Needs review" item, plus "Manual setup" items needing YAML edits (matrix expansion, expression `runs-on`, container/services) -- see mappings.md and gotchas.md
- [ ] Wire up secrets in the YAML: the converter rewrites `${{ secrets.X }}` to `%X%` but does not define it -- store the value (`teamcity project token put <project> <value>`) and add `X: "credentialsJSON:<uuid>"` under the top-level `secrets:` block (see schema.md)
- [ ] Validate: `teamcity pipeline validate <file>` -- only proceed when it passes
- [ ] Create VCS root (`teamcity project vcs create`), then `teamcity pipeline create <name> -p <project> -f <file> --vcs-root <id>`
- [ ] Set up the remaining runtime "Manual setup needed" items before running: registry/cloud connections the steps reference (the first run fails without them), and any `if:`-condition items -- gate converted deploy/release steps via branch filter, execution condition, or a guard in the script so the first run cannot deploy from the wrong branch
- [ ] Run: `teamcity run start <id> --watch`; on failure read `teamcity run log <id> --failed --raw`, fix, `teamcity pipeline push`, re-run until green
- [ ] Do the trigger-only "Manual setup needed" items: triggers, notifications
- [ ] Report: what migrated and what remains manual

References

  • Mappings -- GitHub Actions and Bamboo to TeamCity translation tables
  • Schema -- TC pipeline YAML quick reference
  • Gotchas -- skip list, matrix expansion, troubleshooting, manual setup items
Files (teamcity-cli)
  • references
    • gotchas.md 5.2 KB
      # Sharp Edges, Troubleshooting, and Manual Setup
      
      ## Workflows/jobs to skip (not portable)
      
      Some CI jobs depend on platform-specific infrastructure and cannot be meaningfully migrated:
      
      | Pattern | Why skip |
      |---|---|
      | CodeQL (`github/codeql-action`) | Requires GitHub security-events API and CodeQL cloud infrastructure |
      | Dependabot | GitHub-native dependency update service |
      | GitHub Pages deploy (`actions/deploy-pages`) | GitHub-specific hosting; use TC artifact publishing or separate deploy |
      | GitHub release creation (`on: release`) | The trigger is GitHub-specific; use tag-based VCS trigger in TC instead |
      | Bamboo deployment plans (`bamboo-specs/deployment.yml`) | No TC pipeline equivalent; model as a separate pipeline triggered on build success |
      
      The converter drops the steps it recognizes as non-portable (listed under "Needs review") and emits a no-op placeholder when a job ends up with no steps — delete those placeholders rather than trying to fill them in. Unrecognized variants (e.g. `github/codeql-action/upload-sarif`) become regular TODO stubs instead — decide per stub whether to replace or remove it.
      
      ## Expanding matrix strategies
      
      TC has no native matrix. Expand each matrix combination into a separate job. The key decision is how to pin the language/tool version:
      
      **Use `docker-image` when the job only needs one toolchain.** This is the cleanest approach for language version matrices (Go, Node, Python, etc.):
      
      ```yaml
      test_go_1_21:
        name: "test (Go 1.21)"
        runs-on: Linux-Large
        steps:
          - type: script
            docker-image: "golang:1.21"
            script-content: go test -v -race ./...
      ```
      
      **Install via script when the job needs multiple toolchains.** If a job needs e.g. both a specific Go version AND npm (which isn't in the `golang:` image), run on the agent and install the missing tool:
      
      ```yaml
      build_oldstable:
        name: "build (oldstable)"
        runs-on: Linux-Large
        steps:
          - type: script
            name: "Install Go 1.23"
            script-content: |
              curl -fsSL "https://go.dev/dl/go1.23.8.linux-amd64.tar.gz" -o /tmp/go.tar.gz
              sudo rm -rf /usr/local/go
              sudo tar -C /usr/local -xzf /tmp/go.tar.gz
          - type: script
            script-content: npm install -g some-tool && go test ./...
      ```
      
      **Use the agent default for `stable`/`latest`.** TC Cloud agents have current versions of Go, Node, Java, and Python pre-installed. Only install explicitly when you need a non-default version (e.g. Go's `oldstable` → install the previous minor release).
      
      **Naming convention:** use `<job>_<variant>` IDs — e.g. `test_1_21`, `build_stable`. Job IDs must use `_` not `-`.
      
      **When to simplify instead of expanding.** Large matrices (>6 combinations) produce unwieldy TC pipelines. Pick a representative subset:
      - Keep the latest + oldest supported language versions (drop middle versions)
      - Keep Linux as the primary OS; add macOS/Windows only if the project has platform-specific code
      - For test-tag/flag matrices, keep the default (no flags) + the most important variant (e.g. `-race`)
      - Document what was dropped and why in the manual setup notes
      
      ## Sharp edges
      
      - **`working-directory` scope differs.** In GH Actions it's relative to repo root. In TC it's relative to the checkout directory (usually the same, but verify).
      
      ### Bamboo-specific
      
      - **Variable scopes collapse.** Bamboo has project / plan / job variable scopes. TC pipelines only have pipeline / job / step parameters. Project- and plan-level Bamboo vars need to be merged into the pipeline `parameters:` block manually.
      - **Plan keys aren't IDs.** Bamboo `plan.key: SAMP` ≠ TC pipeline ID. The positional `<name>` argument of `teamcity pipeline create <name>` sets the display name, and TeamCity derives the pipeline ID from it.
      
      ## Troubleshooting
      
      | Failure | Cause | Fix |
      |---|---|---|
      | `Unsupported class file major version 65` | `type: gradle` using agent's old Gradle with newer JDK | Switch to `type: script` + `./gradlew` |
      | `command not found: node/go/python` | Tool not on agent PATH | Check agent, or add setup script |
      | `permission denied` on script | File not executable | Add `chmod +x` step or use `bash script.sh` |
      | Artifact path not found | `files-publication` path doesn't match build output | Check actual output path in build log |
      | Snapshot dependency failed | Upstream job failed | Fix the deepest failed upstream job first |
      
      ## Always-manual setup
      
      | Item | How |
      |---|---|
      | VCS root | `teamcity project vcs list -p <id>` or create in UI |
      | Secrets / GHA `${{ secrets.X }}` / Bamboo `*password*` vars | `teamcity project token put <project-id> "<value>"` |
      | Triggers (GHA `on:`, Bamboo `triggers:`) | Configure push/PR/schedule in TC project settings |
      | Branch filters (GHA `if:`, Bamboo `branches:`) | Add to VCS trigger for conditional jobs |
      | Cloud auth (AWS / GCP / Azure) | TC Connection in project settings |
      | GHA `concurrency:`, `timeout-minutes:`, `fail-fast: false` | Build configuration settings in TC UI |
      | Bamboo `final-tasks:` | Set "Even if some build steps have failed" on each step (UI) |
      | Bamboo `stages[].manual: true` | Manual trigger on the downstream pipeline (UI) |
      | Bamboo plan permissions | TC project roles in Administration → Roles |
      | Bamboo notifications | TC notification rules per user/project |
      
    • mappings.md 12.3 KB
      # Concept Mappings: CI Systems to TeamCity
      
      ## Contents
      
      - GitHub Actions to TeamCity Pipeline YAML (concepts, actions, runners)
      - Fixing a stub
      - Bamboo Specs to TeamCity Pipeline YAML (concepts, tasks, variables)
      - Bamboo Specs that aren't converted
      
      ## GitHub Actions to TeamCity Pipeline YAML
      
      | GitHub Actions | TeamCity | Notes |
      |---|---|---|
      | `jobs.<id>` | `jobs.<id>` | IDs must use `_` not `-` |
      | `steps[].run` | `steps[].script-content` | Shell commands transfer verbatim |
      | `steps[].uses: action` | Depends on action | See action mapping below |
      | `needs: [job1]` | `dependencies: [job1]` | |
      | `runs-on: ubuntu-latest` | `runs-on: Linux-Large` | See runner mapping below |
      | `env.KEY: val` | `parameters: env.KEY: val` | |
      | `secrets.X` | `%X%` | Add `X: "credentialsJSON:<uuid>"` under `secrets:`; create via `teamcity project token put` |
      | `strategy.matrix` | Separate jobs or `parallelism` | |
      | `container: image` | `docker-image:` on steps | |
      | `services:` | Docker Compose or step-level | |
      | `if: condition` | Branch filter or script logic | |
      | `timeout-minutes:` | Build configuration timeout (UI) | No YAML equivalent |
      | `continue-on-error: true` | Wrap the command so its exit code is ignored (`cmd || true`) or override the step's failure condition | TC fails on nonzero exit; the UI step-execution policy only controls running *after* earlier failures — it won't ignore this step's own exit code |
      | `concurrency: { group: ... }` | "Limit max concurrent jobs" build setting (UI) | No YAML equivalent |
      | `outputs:` / `${{ steps.x.outputs.y }}` | `output-parameters:` on producer + `%dep.<job>.<param>%` on consumer | Or write to a shared artifact file |
      | `uses: ./.github/workflows/x.yml` (reusable) | Inline OR convert separately + snapshot dependency | Stub created |
      | `uses: ./.github/actions/x` (composite) | Inline `steps` OR replace with single shell script | Stub created |
      | `on: push/pull_request` | VCS trigger (server-side) | |
      | `on: schedule` | Scheduled trigger (server-side) | |
      | `on: workflow_dispatch` | Manual trigger / parameterized | Inputs become TC build parameters with prompts |
      
      ### Action Mapping
      
      The **Converter emits** column is what `teamcity migrate` writes; **Your follow-up** is what you still have to do by hand.
      
      | Action | Converter emits | Your follow-up |
      |---|---|---|
      | `actions/checkout` | Removed -- TC VCS checkout is automatic | |
      | `actions/cache` | `enable-dependency-cache: true` | |
      | `actions/upload-artifact` | `files-publication: [{path: "..."}]` | |
      | `actions/download-artifact` | Nothing (simplified out); named downloads get a manual note | Artifacts arrive via the job's `dependencies:` (from `needs:`) -- ensure the upstream job publishes with `share-with-jobs: true`, and add the dependency yourself if the workflow downloaded from a job it didn't `need` |
      | `actions/setup-node/java/go/python` | Removed -- pre-installed on TC Cloud agents | Pinned versions surface as manual notes; ensure the agent provides them |
      | `gradle/actions/setup-gradle` | Removed -- `./gradlew` runs directly | |
      | `docker/login-action` | Comment-only placeholder step | Configure a Docker registry connection in TC project settings -- required for private registries, no login command is generated |
      | `docker/build-push-action` | `docker build && docker push` script | |
      | `JetBrains/qodana-action` | Commented pointer to native integration | Add the Qodana build feature in TC settings |
      | `aws-actions/configure-aws-credentials` | Nothing (simplified out); a manual note carries the wiring | Add `env.AWS_ACCESS_KEY_ID` / `env.AWS_SECRET_ACCESS_KEY` under `secrets:` and `env.AWS_DEFAULT_REGION` under the job's `parameters:` -- step-local exports would not survive across TC steps |
      | `softprops/action-gh-release` | `gh release create "<tag_name>" --generate-notes` plus any `files:` globs; falls back to `%teamcity.build.branch%` when `tag_name` is unset | Add `env.GH_TOKEN` under `secrets:` -- `gh` reads it from the environment, so the `env.` prefix is required |
      | `golangci/golangci-lint-action` | `golangci-lint run <args>` | Assumes the binary on the agent; a pinned `version:` becomes a manual note -- install it yourself |
      | `codecov/codecov-action` | `curl -Os https://cli.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov` | |
      | `goreleaser/goreleaser-action` | **Stub** (not in the registry) | Replace with `curl -sSfL https://goreleaser.com/static/run \| bash -s -- release --clean` (needs `GITHUB_TOKEN`) |
      | `aquasecurity/trivy-action` | `trivy <scan-type> <image-ref>` | Assumes trivy on the agent; install via the trivy install.sh if missing |
      | `github/codeql-action/init`, `/analyze`, `/autobuild` | **Dropped** (listed under Needs review) -- requires GitHub security-events API | Consider the Qodana build feature instead. Other codeql-action subpaths (e.g. `/upload-sarif`) stub like unknown actions |
      | Unknown actions | Commented stub with original inputs | Read the action's source, write the equivalent shell |
      
      ### Fixing a stub
      
      The converter emits unknown actions as commented TODO steps that preserve the original inputs:
      
      ```yaml
      - type: script
        name: "custom-deploy"
        script-content: |-
          # TODO: Replace acme/custom-deploy@v2 with equivalent commands
          # Action inputs:
          #   region: eu-west-1
          #   target: prod
          echo 'TODO: implement equivalent of custom-deploy'
      ```
      
      Read the action's repository -- its `action.yml` shows what it actually runs (most actions are thin CLI wrappers). Replace the step body with the equivalent commands:
      
      ```yaml
      - type: script
        name: "custom-deploy"
        script-content: aws deploy create-deployment --region eu-west-1 --deployment-group prod
      ```
      
      Secrets referenced by the original inputs become `%PARAM%` references -- create them with `teamcity project token put`.
      
      ### Runner Mapping
      
      | GitHub Actions | TeamCity Cloud |
      |---|---|
      | `ubuntu-latest` / `ubuntu-24.04` / `ubuntu-22.04` | `Linux-Large` |
      | `macos-latest` / `macos-15` / `macos-14` | `Mac-Medium` |
      | `windows-latest` / `windows-2022` | `Windows-Medium` |
      | Self-hosted labels | `self-hosted` with agent requirements |
      
      Hosted agent names come from the server's pipeline schema (`runs-on` enum, e.g. `Linux-Small/Medium/Large/XLarge`, `Mac-Medium`, `Windows-Small/Medium`). When connected, the CLI derives this mapping from the live schema — check `teamcity pipeline schema` if a name is rejected.
      
      ## Bamboo Specs to TeamCity Pipeline YAML
      
      Bamboo Specs YAML lives in `bamboo-specs/*.yml` (or `bamboo.yml` in the repo root). The converter walks `stages → jobs → tasks` and turns each task into a TeamCity step.
      
      | Bamboo concept | TeamCity | Notes |
      |---|---|---|
      | `plan` (project-key, key, name) | Pipeline + project | Project must exist before `pipeline create` |
      | `stages[]` ordered list | Job dependencies | Stage N's jobs `dependencies:` all stage N-1 jobs |
      | `stages[].manual: true` | Manual approval | Surfaced as manual setup; use TC manual trigger or approval feature |
      | `stages[].final: true` | Final cleanup job | Set step execution policy to "Even if some build steps have failed" |
      | Top-level job def (e.g. `Build:`) | TC job | Job ID becomes `<Stage>_<Job>` (sanitized) |
      | `tasks[]` | `steps[]` | Each task transformed individually; unknowns become TODO stubs |
      | `final-tasks[]` | Steps with always-run policy | Surfaced as manual setup; set per-step `Even if some build steps have failed` |
      | `artifacts[]` | `files-publication[]` | `shared: true` → `share-with-jobs`; otherwise `publish-artifact` |
      | `artifact-subscriptions[]` | Artifact dependencies | Manual: add to pipeline `dependencies:` block |
      | `requirements[]` | `runs-on` + agent requirements | First OS-shaped entry picks the runner; non-OS entries become manual notes. With no OS requirement, OS-bound tasks (ms-build, fastlane, xcode, ...) infer it |
      | `docker.image` | Docker container settings | Surfaced as manual setup; wrap step or use Docker wrapper feature |
      | `triggers[]` (polling, cron, ...) | VCS / scheduled triggers | Manual; configure in TC UI |
      | `branches:` | VCS root branch filters | Manual; configure on the VCS root |
      | `dependencies:` (top-level plan deps) | Cross-pipeline `dependencies:` or snapshot dependencies | Manual |
      | `variables:` | Pipeline parameters | Lifted to top-level `parameters:` |
      | `${bamboo.foo}` references | `%foo%` (TC parameter) | Predefined names map to TC equivalents (see below) |
      | `plan-permissions:` | Project roles | Manual; configure in TC Administration → Roles |
      | `notifications:` | Notification rules | Manual; configure per project/user |
      
      ### Bamboo Task Mapping
      
      | Bamboo task | TeamCity step | Notes |
      |---|---|---|
      | `script` | `type: script` | Shorthand list and full form (`scripts:`, `interpreter:`) supported |
      | `checkout` | Remove -- TC VCS checkout is automatic | |
      | `clean` | Remove -- enable "Clean checkout" on VCS root | |
      | `maven` / `mvn2` / `mvn3` | `mvn -f <project> <goal>` | JDK and `tests:` flag surface as manual notes |
      | `ant` | `ant -f <buildfile> <target>` | |
      | `gradle` | `./gradlew <tasks>` | |
      | `npm` | `npm <command>` | |
      | `node` | `node <script> <args>` | |
      | `command` | Inline `<exe> <args>` | |
      | `docker` (build/push/run) | `docker <cmd> ...` | Registry login is not converted or flagged -- add `docker login` or a TC registry connection yourself |
      | `inject-variables` | `set -a; . file; set +a` | Manual: review whether to convert to TC parameters |
      | `dump-variables` | `env \| sort` | |
      | `artifact-download` | Manual artifact-dependency | Surfaced as manual setup |
      | `test-parser` / `j_unit` / `nunit-parser` / `mocha` | Remove -- TC has built-in test report import | Manual: confirm report path |
      | `ssh` / `scp` | Inline `ssh`/`scp` script | Manual: upload SSH key with `teamcity project ssh upload` |
      | `ms-build` / `ms-test` / `visual-studio` / `nunit-runner` | Inline equivalent commands | |
      | `fastlane` | `fastlane <lane>` | |
      | `unlock-keychain` | `security unlock-keychain ...` | Manual: store password as TC token |
      | `repository-tag` / `repository-branch` / `repository-commit` / `repository-push` | Inline `git` commands | Push credentials are not flagged -- ensure the agent has them |
      | `aws-code-deploy` | `aws deploy create-deployment ...` | Manual: store AWS credentials as TC tokens |
      | `grails` / `gulp` / `grunt` / `bower` | Inline runner invocation | |
      | Unknown task | Commented TODO stub with original fields | |
      
      ### Bamboo Variable Mapping
      
      `${bamboo.foo}` references in task fields map to TC parameter syntax:
      
      | Bamboo | TeamCity |
      |---|---|
      | `${bamboo.build.number}` | `%build.number%` |
      | `${bamboo.repository.revision.number}` | `%build.vcs.number%` |
      | `${bamboo.repository.branch.name}` | `%teamcity.build.branch%` |
      | `${bamboo.repository.git.repositoryUrl}` | `%vcsroot.url%` |
      | `${bamboo.working.directory}` | `%teamcity.build.checkoutDir%` |
      | `${bamboo.tmp.directory}` | `%system.teamcity.build.tempDir%` |
      | `${bamboo.buildPlanName}` | `%teamcity.buildConfName%` |
      | `${bamboo.planKey}` / `${bamboo.buildKey}` | `%system.teamcity.buildType.id%` |
      | `${bamboo.agentId}` | `%teamcity.agent.id%` |
      | `${bamboo.build.timeStamp}` | `%build.start.date.timestamp%` |
      | `${bamboo.<custom>}` | `%<custom>%` (define in TC project parameters) |
      | `${SHELL_VAR}` (no `bamboo.` prefix) | Left untouched (treated as shell expansion) |
      
      ### Bamboo Specs that aren't converted
      
      These constructs land in the bamboo-specs directory but the migrate command does not auto-convert them — handle manually:
      
      | Bamboo construct | TeamCity handling |
      |---|---|
      | `bamboo-specs/deployment.yml` (deployment plans) | Model as a separate pipeline triggered on the build pipeline's success; or use TC deployment build configuration |
      | Multi-document specs (`---`-separated) | The converter handles the first `plan:` document and flags the rest under Needs review -- split remaining documents into separate files and re-run `teamcity migrate` |
      | `repositories:` block (project-level VCS declarations) | Run `teamcity project vcs create` for each repo before pipeline creation |
      | `other:` block (`concurrent-build-plugin`, `clean-working-dir`, ...) | Configure cleanup/concurrency in TC build settings UI |
      | `linked-repositories:` | Manual: create TC VCS roots and reference by ID |
      | Stages/jobs whose names collide after sanitizing | The converter de-duplicates job IDs with `_2` suffixes, but `dependencies:` referencing the duplicated name resolve to the *first* job -- verify the generated `dependencies:` blocks |
      
      
    • schema.md 3.8 KB
      # TeamCity Pipeline YAML Quick Reference
      
      ## Contents
      
      - Structure (full annotated example)
      - Step Types (script, gradle, maven, node-js)
      - Agent Types (TeamCity Cloud + self-hosted)
      - Dependencies Between Jobs
      - Files / Artifacts
      - Validating (and what `validate` does NOT check)
      
      ## Structure
      
      ```yaml
      jobs:
        <job_id>:              # Alphanumeric + underscores only
          name: "Display Name"
          runs-on: <agent>     # See agent types below
          parameters:          # Job-scoped env vars
            env.KEY: "value"
          enable-dependency-cache: true    # Replaces manual caching
          dependencies:        # Jobs that must complete first
            - other_job_id
          steps:
            - type: script     # or: gradle, maven, node-js
              name: "Step Name"
              script-content: |
                echo "hello"
          files-publication:   # Artifacts
            - path: "build/**"
              share-with-jobs: true       # Downstream jobs can access
              publish-artifact: true      # Visible in build results
      
      parameters:              # Pipeline-scoped env vars
        env.GLOBAL_KEY: "value"
      
      secrets:                 # Sensitive values — value MUST start with "credentialsJSON:"
        API_KEY: "credentialsJSON:uuid-here"   # referenced as %API_KEY% (matches converter output)
                                               # env.-prefixed keys become environment variables instead
      ```
      
      ## Step Types
      
      ### `type: script`
      ```yaml
      - type: script
        name: "Run tests"
        script-content: npm test
        working-directory: "subdir"     # Optional
        docker-image: "node:20"        # Optional: run in container
      ```
      
      ### `type: gradle`
      ```yaml
      - type: gradle
        name: "Build"
        gradle-params: clean build -x test
      ```
      
      ### `type: maven`
      ```yaml
      - type: maven
        name: "Build"
        goals: clean package -DskipTests
      ```
      
      ### `type: node-js`
      ```yaml
      - type: node-js
        name: "Build"
        shell-script: npm run build
      ```
      
      ## Agent Types (TeamCity Cloud)
      
      Hosted agent names come from the server's pipeline schema — see the runner mapping in [mappings](mappings.md). For self-hosted agents:
      ```yaml
      runs-on:
        self-hosted:
          - os-family: Linux
          - arch: aarch64
      ```
      
      ## Dependencies Between Jobs
      
      ```yaml
      jobs:
        build:
          steps: [...]
      
        test:
          dependencies:
            - build              # Simple: wait for build to finish
          steps: [...]
      
        deploy:
          dependencies:
            - build:
                reuse: successful  # Reuse if nothing changed
            - test
          steps: [...]
      ```
      
      ## Files / Artifacts
      
      ```yaml
      jobs:
        build:
          files-publication:
            - path: "dist/**"
              share-with-jobs: true      # Other jobs can download
              publish-artifact: true     # Show in UI
      
        deploy:
          dependencies:
            - build                      # Artifacts available automatically
          download-artifacts:            # From external build configs (NOT in this pipeline)
            - ExternalConfig_ID:
                from: last-successful
                artifact-rules: "*.jar => lib/"
      ```
      
      `download-artifacts:` is for pulling artifacts from a build configuration outside the current pipeline. For artifacts produced by an upstream job in the same pipeline, declare a `dependencies:` link and mark the artifact `share-with-jobs: true` on the producer — TC then makes them available automatically.
      
      ## Validating
      
      ```bash
      teamcity pipeline validate my-pipeline.tc.yml
      ```
      
      ### What `validate` does NOT check
      
      The schema validates structure (jobs/steps shape, types, secret format, runner field types) but not the inner shape of each step type. That means:
      
      - A misspelled key like `script-conent:` will pass schema validation and fail at runtime.
      - `type: gradle` with no `gradle-params` may pass schema but produce an empty build.
      - Keys that don't exist (`if:`, `interruptible:`, `timeout:`) pass schema but are silently ignored at runtime.
      
      Treat `pipeline validate` as a fast structural check, not proof of correctness.
      
  • SKILL.md 5.1 KB
    ---
    name: migrate-to-teamcity
    version: "0.3.0"
    description: Migrating CI/CD pipelines to TeamCity. Use when the user wants to migrate, convert, or switch to TeamCity from GitHub Actions (.github/workflows/) or Bamboo (bamboo-specs/*.yml), even if they only say "move our CI". Other CI systems (GitLab, Jenkins, CircleCI, Azure DevOps, Travis, Bitbucket) are not supported yet.
    ---
    
    # Migrate to TeamCity
    
    ## Quick Start
    
    ```bash
    teamcity migrate                    # detect + convert + write .tc.yml files
    teamcity migrate --dry-run --json   # preview as structured JSON
    teamcity pipeline validate f.tc.yml # schema check
    teamcity project vcs create --url <repo-url> --auth anonymous -p ProjectId  # create VCS root first
    teamcity pipeline create name -p ProjectId -f f.tc.yml --vcs-root <VcsRootId>
    teamcity run start PipelineId --watch
    ```
    
    Run `teamcity migrate` from the repo root -- detection scans `.github/workflows/` and `bamboo-specs/` relative to the current directory.
    
    ## Reading the report
    
    - **Needs review** -- problems inside the generated YAML: TODO stubs, dropped steps, reusable-workflow placeholders. Fix these in the file before creating the pipeline.
    - **Manual setup needed** -- work the converter cannot do. Sort each item onto one of two sides: YAML edits (secrets, matrix expansion, expression `runs-on`, `container:`/`services:`) go before `pipeline create`; server-side configuration (connections, `if:`-derived branch filters, triggers, notifications) comes after. The checklist below orders them.
    - Exit code 1 means at least one source failed to convert *or* one generated file failed schema validation -- files that converted cleanly are still written. Read the per-file ✓/⚠/✗ lines instead of treating exit 1 as total failure.
    - `--json` prints `{"sources": [...], "results": [...]}` to stdout; each result carries `outputFile`, `yaml`, `needsReview`, `manualSetup`, and `validationError`.
    
    ## Gotchas
    
    - **Always `type: script` for `./gradlew` and `./mvnw`.** TC's `type: gradle`/`type: maven` runners use the agent's version, not the project's. This causes real build failures.
    - **Schema valid does not mean pipeline works.** Migration is not done until builds pass.
    - **Private repos: use a GitHub App connection, not a PAT.** Start with `teamcity project connection create github-app -p <project>` -- its output prints the authorize, App-install, and `vcs create` follow-up commands. That flow opens a browser; in headless runs pass existing App credentials (`--no-manifest --app-id <id> --client-id <id> --private-key-file <pem> --stdin`, client secret piped to stdin) or use SSH deploy keys (`teamcity project ssh upload` with a `git@github.com:` URL). Public repos: `--auth anonymous`.
    - **Secrets, triggers, and branch filters are always manual.** The converter flags them but cannot create them -- the checklist below covers each.
    - **VCS root must exist before pipeline create.** `teamcity pipeline create` takes `--vcs-root <id>`, not a URL. Create it first with `teamcity project vcs create`.
    - **Default branch defaults to `main`.** Pass `--branch refs/heads/master` to `teamcity project vcs create` if the repo uses `master`.
    - **Unknown actions/tasks become stubs.** Read the action's source, write an equivalent shell script. Most actions are thin CLI wrappers. See [mappings](references/mappings.md).
    
    ## Workflow
    
    Goal: get all pipeline jobs green on the TC server, not just generate valid YAML.
    
    Copy this checklist and check off items as you complete them:
    
    ```
    Migration progress:
    - [ ] Convert: run `teamcity migrate` from the repo root
    - [ ] Fix every "Needs review" item, plus "Manual setup" items needing YAML edits (matrix expansion, expression `runs-on`, container/services) -- see mappings.md and gotchas.md
    - [ ] Wire up secrets in the YAML: the converter rewrites `${{ secrets.X }}` to `%X%` but does not define it -- store the value (`teamcity project token put <project> <value>`) and add `X: "credentialsJSON:<uuid>"` under the top-level `secrets:` block (see schema.md)
    - [ ] Validate: `teamcity pipeline validate <file>` -- only proceed when it passes
    - [ ] Create VCS root (`teamcity project vcs create`), then `teamcity pipeline create <name> -p <project> -f <file> --vcs-root <id>`
    - [ ] Set up the remaining runtime "Manual setup needed" items before running: registry/cloud connections the steps reference (the first run fails without them), and any `if:`-condition items -- gate converted deploy/release steps via branch filter, execution condition, or a guard in the script so the first run cannot deploy from the wrong branch
    - [ ] Run: `teamcity run start <id> --watch`; on failure read `teamcity run log <id> --failed --raw`, fix, `teamcity pipeline push`, re-run until green
    - [ ] Do the trigger-only "Manual setup needed" items: triggers, notifications
    - [ ] Report: what migrated and what remains manual
    ```
    
    ## References
    
    - [Mappings](references/mappings.md) -- GitHub Actions and Bamboo to TeamCity translation tables
    - [Schema](references/schema.md) -- TC pipeline YAML quick reference
    - [Gotchas](references/gotchas.md) -- skip list, matrix expansion, troubleshooting, manual setup items
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related