npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thinesjs/cmenv

v0.0.1

Published

Sync environment variables from codemagic.plains.yaml to Codemagic all through CLI.

Readme

cmenv-cli

CLI tool for syncing environment variables to Codemagic from a version-controlled YAML config.

Define your variable groups in codemagic.plains.yaml, keep secrets in a gitignored codemagic.secrets.yaml, and sync them to Codemagic with a single command.

Install

npm install -g @thinesjs/cmenv

Or run directly:

npx @thinesjs/cmenv sync --dry-run

Quick Start

1. Add to .gitignore

# cmenv
codemagic.config.json
codemagic.secrets.yaml
.codemagic/

2. Create codemagic.plains.yaml

This is the source of truth for your Codemagic variable groups. Committed to git.

groups:
  global-vars:
    variables:
      - name: NODEJS_VERSION
        value: "22"

  staging-vars:
    secure: true
    variables:
      - name: BUILD_ENV
        value: "staging"
      - name: BUNDLE_ID
        value: "com.example.app.staging"
        secure: false
      - name: GOOGLE_SERVICES_JSON
        file: staging/google-services.json
      - name: GOOGLE_SERVICES_PLIST
        file: staging/GoogleService-Info.plist
      - name: ENV_STAGING
        file: staging/.env.staging

  prod-vars:
    secure: true
    variables:
      - name: BUILD_ENV
        value: "production"
      - name: BUNDLE_ID
        value: "com.example.app"
        secure: false
      - name: PROD_BUILD_NUMBER
        value: "1"
        secure: false
      - name: GOOGLE_SERVICES_JSON
        file: production/google-services.json
      - name: GOOGLE_SERVICES_PLIST
        file: production/GoogleService-Info.plist
      - name: ENV_PRODUCTION
        file: production/.env.production
      - name: FIREBASE_SERVICE_ACCOUNT
        file_raw: credentials/firebase-service-account.json

  ios-global-vars:
    variables:
      - name: XCODE_VERSION
        value: "26.1"
      - name: COCOAPODS_VERSION
        value: "1.16.2"
      - name: RUBY_VERSION
        value: "3.4.1"
      - name: XCODE_WORKSPACE
        value: "MyApp.xcworkspace"
      - name: XCODE_SCHEME
        value: "MyApp"

3. Create codemagic.config.json (gitignored)

{
  "api_key": "your-codemagic-api-key",
  "team_id": "your-team-id",
  "app_id": "your-app-id"
}

4. Set up .codemagic/ directory (gitignored)

Drop your secret files here. File paths in the YAML resolve relative to this directory.

.codemagic/
├── staging/
│   ├── google-services.json
│   ├── GoogleService-Info.plist
│   └── .env.staging
├── production/
│   ├── google-services.json
│   ├── GoogleService-Info.plist
│   └── .env.production
└── credentials/
    └── firebase-service-account.json

5. Sync

cmenv sync --dry-run    # preview
cmenv sync --update     # push to codemagic
cmenv list              # verify remote state

6. Compatible codemagic.yaml

Minimal Codemagic workflow config that works with the variable groups above:

definitions:
  environments:
    - &base_env
      vars:
        CM_CLONE_DEPTH: 3

    - &android_base_env
      node: $NODEJS_VERSION
      android_signing:
        - your-keystore-name

    - &ios_base_env
      node: $NODEJS_VERSION
      xcode: $XCODE_VERSION
      cocoapods: $COCOAPODS_VERSION
      ruby: $RUBY_VERSION

    - &ios_appstore_signing
      distribution_type: app_store
      bundle_identifier: $BUNDLE_ID

    - &ios_adhoc_signing
      distribution_type: ad_hoc
      bundle_identifier: $BUNDLE_ID

  env_groups:
    - &staging_android_groups
      - global-vars
      - staging-vars

    - &staging_ios_groups
      - global-vars
      - ios-global-vars
      - staging-vars

    - &prod_android_groups
      - global-vars
      - prod-vars

    - &prod_ios_groups
      - global-vars
      - ios-global-vars
      - prod-vars

  steps:
    - step: &android_files_config
        name: Load Android files configuration
        script: |
          #!/usr/bin/env sh
          set -e
          echo $GOOGLE_SERVICES_JSON | base64 --decode > android/app/src/$BUILD_ENV/google-services.json

    - step: &ios_files_config
        name: Load iOS files configuration
        script: |
          #!/usr/bin/env sh
          set -e
          echo $GOOGLE_SERVICES_PLIST | base64 --decode > ios/GoogleService-Info.plist

    - step: &set_android_sdk_location
        name: Set Android SDK location
        script: echo "sdk.dir=$ANDROID_SDK_ROOT" > "android/local.properties"

    - step: &install_deps
        name: Install dependencies
        script: yarn install

    - step: &install_cp_deps
        name: Install CocoaPods dependencies
        script: |
          gem install cocoapods -v $COCOAPODS_VERSION
          gem install xcpretty
          cd ios && pod install

    - step: &generate_env_staging
        name: Export .env.staging
        script: |
          PACKAGE_VERSION=$(cat package.json | jq -r '.version')
          UPDATED_BUILD_NUMBER=$((10000 + $PROJECT_BUILD_NUMBER))
          echo $ENV_STAGING | base64 --decode > .env.staging
          echo "APP_BUILD_NUMBER=$UPDATED_BUILD_NUMBER" >> .env.staging
          echo "APP_VERSION=$PACKAGE_VERSION" >> .env.staging

    - step: &generate_env_prod
        name: Export .env.production
        script: |
          PACKAGE_VERSION=$(cat package.json | jq -r '.version')
          echo $ENV_PRODUCTION | base64 --decode > .env.production
          echo "APP_BUILD_NUMBER=$PROD_BUILD_NUMBER" >> .env.production
          echo "APP_VERSION=$PACKAGE_VERSION" >> .env.production

  signing_steps:
    - step: &setup_adhoc_code_signing
        name: Set up ad-hoc code signing
        script: |
          keychain initialize
          app-store-connect fetch-signing-files "$BUNDLE_ID" --type IOS_APP_ADHOC --create
          keychain add-certificates
          xcode-project use-profiles --project ios/*.xcodeproj --archive-method=ad-hoc

    - step: &setup_appstore_code_signing
        name: Set up App Store code signing
        script: |
          keychain initialize
          app-store-connect fetch-signing-files "$BUNDLE_ID" --type IOS_APP_STORE --create
          keychain add-certificates
          xcode-project use-profiles --project ios/*.xcodeproj

  builds:
    - step: &build_android_staging
        name: Build Android staging
        script: cd android && ./gradlew assembleStagingRelease

    - step: &build_android_prod
        name: Build Android production
        script: cd android && ./gradlew bundleProductionRelease

    - step: &build_ios
        name: Build iOS IPA
        script: |
          xcode-project build-ipa \
            --workspace "ios/$XCODE_WORKSPACE" \
            --scheme "$XCODE_SCHEME"

workflows:
  staging-android-release:
    name: "[Android] Staging Release"
    max_build_duration: 60
    instance_type: linux_x2
    environment:
      <<: [*base_env, *android_base_env]
      groups: *staging_android_groups
    scripts:
      - *set_android_sdk_location
      - *android_files_config
      - *generate_env_staging
      - *install_deps
      - *build_android_staging

  staging-ios-release:
    name: "[iOS] Staging Release"
    max_build_duration: 60
    instance_type: mac_mini_m2
    environment:
      <<: [*base_env, *ios_base_env]
      groups: *staging_ios_groups
      ios_signing:
        <<: *ios_adhoc_signing
    scripts:
      - *ios_files_config
      - *generate_env_staging
      - *install_deps
      - *install_cp_deps
      - *setup_adhoc_code_signing
      - *build_ios

  production-android-release:
    name: "[Android] Production Release"
    max_build_duration: 60
    instance_type: mac_mini_m2
    environment:
      <<: [*base_env, *android_base_env]
      groups: *prod_android_groups
    scripts:
      - *set_android_sdk_location
      - *android_files_config
      - *generate_env_prod
      - *install_deps
      - *build_android_prod
    publishing:
      google_play:
        credentials: $FIREBASE_SERVICE_ACCOUNT
        track: internal
        submit_as_draft: true

  production-ios-release:
    name: "[iOS] Production Release"
    max_build_duration: 60
    instance_type: mac_mini_m2
    integrations:
      app_store_connect: codemagic
    environment:
      <<: [*base_env, *ios_base_env]
      groups: *prod_ios_groups
      ios_signing:
        <<: *ios_appstore_signing
    scripts:
      - *ios_files_config
      - *generate_env_prod
      - *install_deps
      - *install_cp_deps
      - *setup_appstore_code_signing
      - *build_ios
    publishing:
      app_store_connect:
        auth: integration
        submit_to_testflight: true

File Structure

| File | Committed | Purpose | |------|-----------|---------| | codemagic.plains.yaml | Yes | Variable groups and non-secret values | | codemagic.secrets.yaml | No | Secret values, merged into plains at sync time | | codemagic.config.json | No | Codemagic API credentials | | .codemagic/ | No | Secret files referenced by file / file_raw |

Only codemagic.plains.yaml is required.

Variable Definitions

Variables support three value sources:

groups:
  my-group:
    secure: true  # default secure flag for all variables in group
    variables:
      # inline value
      - name: API_URL
        value: "https://api.example.com"

      # file reference — base64-encoded at sync time, secure by default
      - name: GOOGLE_SERVICES_JSON
        file: staging/google-services.json

      # raw file reference — read as-is, secure by default
      - name: SERVICE_ACCOUNT
        file_raw: credentials/service-account.json

      # per-variable secure override
      - name: BUILD_NUMBER
        value: "42"
        secure: false

File paths (file, file_raw) resolve relative to the .codemagic/ directory.

Secrets

codemagic.secrets.yaml uses the same format as the plains file. At sync time, it's deep-merged into the plains config:

  • Variables are matched by name within each group
  • Secrets file wins on conflict
  • New variables are appended
  • New groups are added
# codemagic.secrets.yaml
groups:
  my-group:
    variables:
      - name: API_KEY
        value: "sk-live-abc123"

Commands

sync

cmenv sync                    # sync all groups (create only)
cmenv sync --update           # create + update existing
cmenv sync --dry-run          # preview without changes
cmenv sync --group <name>     # sync specific group
cmenv sync --delete-extra     # remove remote vars not in config

list

cmenv list                    # show remote groups and variables

clean

cmenv clean --group <name> --dry-run   # preview deletions
cmenv clean --group <name> --yes       # delete variables in group
cmenv clean --all --yes                # delete all variables
cmenv clean --all --delete-groups --yes # delete groups too

Credentials

Resolved in this order (first wins):

  1. CLI flags: --api-key, --team-id, --app-id
  2. codemagic.config.json (sibling of plains file)
  3. Environment variables: CODEMAGIC_API_KEY, CODEMAGIC_TEAM_ID, CODEMAGIC_APP_ID

--env-file <path> loads a dotenv file into the environment before credential resolution.

Config Discovery

cmenv finds codemagic.plains.yaml automatically:

  1. --config <path> flag (explicit)
  2. Current working directory
  3. Walk up parent directories

Once found, sibling files (codemagic.secrets.yaml, codemagic.config.json) and .codemagic/ are resolved relative to the same directory.

License

MIT