This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

EAS 工作流语法

编辑页面

EAS 工作流配置文件语法参考指南。


A workflow is a configurable automated process made up of one or more jobs. You must create a YAML file to define your workflow configuration.

To get started with workflows, see Get Started with EAS Workflows or see Examples for complete workflow configurations.

Workflow files

Workflow files use YAML syntax, must have either a .yml or .yaml file extension, and must be 16 KiB or smaller. If you're new to YAML and want to learn more, see Learn YAML in Y minutes.

Workflow files are located in the .eas/workflows directory in your project. The .eas directory should be at the same level as your eas.json file.

For example:

my-app
 .eas
  workflows
   create-development-builds.yml
   publish-preview-update.yml
   deploy-to-production.yml
 eas.json

Configuration reference

Below is a reference for the syntax of the workflow configuration file.

name

The human-friendly name of the workflow. This is displayed on the EAS dashboard on the workflows list page and is the title of the workflow's detail page. To set a title for each individual run, use run_name.

name: My workflow

run_name

The title of an individual workflow run. This is separate from name, which labels the workflow itself.

name: Deploy run_name: Deploy ${{ inputs.environment }} on: workflow_dispatch: inputs: environment: type: choice options: - preview - production required: true

The value is a string. It can include ${{ }} expressions. EAS renders the template when it creates the run, before any job starts.

The expression can use the github, app_store_connect, inputs, workflow, app, and account contexts. It supports all context functions except success(), failure(), and hashFiles(). Those functions need a job or step that has already run.

Job-level contexts such as needs, steps, and env are not available. If the template references an unsupported context, the run fails. EAS stores an error and does not store a custom title.

If the rendered text is longer than 255 characters, EAS truncates it to 254 characters and appends an ellipsis.

on

The on key defines which GitHub events trigger the workflow. Any workflow can be triggered with the eas workflow:run command, regardless of the on key.

on: # Trigger on pushes to main branch push: branches: - main # And on pull requests starting with 'version-' pull_request: branches: - version-*

on.push

Runs your workflow when you push a commit to matching branches and/or tags.

With the branches list, you can trigger the workflow only when those specified branches are pushed to. For example, if you use branches: ['main'], only pushes to the main branch trigger the workflow. Supports globs. By using the ! prefix you can specify branches to ignore (you still need to provide at least one branch pattern without it).

With the tags list, you can trigger the workflow only when those specified tags are pushed. For example, if you use tags: ['v1'], only the v1 tag being pushed triggers the workflow. Supports globs. By using the ! prefix you can specify tags to ignore (you still need to provide at least one tag pattern without it).

With the paths list, you can trigger the workflow only when changes are made to files matching the specified paths. For example, if you use paths: ['apps/mobile/**'], only changes to files in the apps/mobile directory trigger the workflow. Supports globs. By default, changes to any path trigger the workflow.

When neither branches nor tags are provided, branches defaults to ['*'] and tags defaults to [], which means the workflow triggers on push events to all branches and does not trigger on tag pushes. If only one of the two lists is provided the other defaults to [].

With the if: condition, you can decide whether a workflow run starts.

on: push: branches: - main - feature/** - !feature/test-** # other branch names and globs tags: - v1 - v2* - !v2-preview** # other tag names and globs paths: - apps/mobile/** - packages/shared/** - !**/*.md # ignore markdown files

on.ref_delete

Runs your workflow when a GitHub branch or tag is deleted. Requires a linked GitHub repository on your EAS project.

With the branches list, you can trigger the workflow only when those specified branches are deleted. For example, if you use branches: ['feat/**'], only deletion of branches matching feat/** triggers the workflow. Supports globs. By using the ! prefix you can specify branches to ignore (you still need to provide at least one branch pattern without it). See on.push for details on glob and negation pattern matching.

With the tags list, you can trigger the workflow only when those specified tags are deleted. Supports globs and ! negation with the same rules as branches.

When neither branches nor tags are provided, branches defaults to ['*'] and tags defaults to [], which means the workflow triggers when any branch is deleted and does not trigger on tag deletions. If only one of the two lists is provided the other defaults to [].

With the if: condition, you can decide whether a workflow run starts.

Pair this trigger with the branch-delete job to remove EAS Update branches when GitHub branches are deleted. See the Clean up update branches example for a complete workflow.

on: ref_delete: branches: - feat/** - !main # other branch names and globs tags: - v* - !v2-preview** # other tag names and globs

on.pull_request

Runs your workflow when you create or update a pull request that targets one of the matching branches.

With the branches list, you can trigger the workflow only when those specified branches are the target of the pull request. For example, if you use branches: ['main'], only pull requests to merge into the main branch trigger the workflow. Supports globs. Defaults to ['*'] when not provided, which means the workflow triggers on pull request events to all branches. By using the ! prefix you can specify branches to ignore (you still need to provide at least one branch pattern without it).

With the types list, you can trigger the workflow only on the specified pull request event types. For example, if you use types: ['opened'], only the pull_request.opened event (sent when a pull request is first opened) triggers the workflow. Defaults to ['opened', 'reopened', 'synchronize'] when not provided. Supported event types:

  • opened
  • edited
  • base_ref_changed
  • ready_for_review
  • reopened
  • synchronize
  • labeled

The edited type follows GitHub's pull_request.edited behavior and triggers when the pull request title, body, or base branch changes. To trigger only when the pull request's base branch changes, use base_ref_changed.

The branches filter matches the pull request's current base branch, so retargeting a pull request to a matching branch can trigger a workflow.

With the paths list, you can trigger the workflow only when changes are made to files matching the specified paths. For example, if you use paths: ['apps/mobile/**'], only changes to files in the apps/mobile directory trigger the workflow. Supports globs. By default, changes to any path trigger the workflow.

You can add an if: condition to decide whether a workflow run starts.

on: pull_request: branches: - main - feature/** - !feature/test-** # other branch names and globs types: - opened # other event types paths: - apps/mobile/** - packages/shared/** - !**/*.md # ignore markdown files

on.pull_request_labeled

Runs your workflow when a pull request is labeled with a matching label.

With the labels list, you can specify which labels, when assigned to your pull request, trigger the workflow. For example, if you use labels: ['Test'], only labeling a pull request with the Test label triggers the workflow. Defaults to [] when not provided, which means no labels trigger the workflow.

To decide whether a workflow run starts, add an if: condition.

You can also provide a list of matching labels directly to on.pull_request_labeled for simpler syntax.

on: pull_request_labeled: labels: - Test - Preview # other labels

Alternatively:

on: pull_request_labeled: - Test - Preview # other labels

on.pull_request_comment

Runs your workflow when someone creates, edits, or deletes a comment on a pull request.

With the types list, you can specify which events trigger the workflow. Defaults to ['created'] when not provided. Supported event types:

  • created
  • edited
  • deleted

Unlike on.pull_request, this trigger has no branches or paths filter.

With the if: condition, you can decide whether a workflow run starts.

on: pull_request_comment: types: - created - edited # other event types

on.app_store_connect

Runs your workflow when one of the selected App Store Connect events occurs.

When on.app_store_connect is present, you must specify at least one event domain (app_version, build_upload, external_beta, or beta_feedback). Within a configured event domain, you can specify which states should trigger your workflow.

Each event domain also accepts an if: condition, so you can decide whether a workflow run starts.

on.app_store_connect.app_version.states

Filters app store app version state change events. Defaults to all supported app version states when not provided.

Supported values:

  • accepted
  • developer_rejected
  • in_review
  • invalid_binary
  • metadata_rejected
  • pending_apple_release
  • pending_developer_release
  • prepare_for_submission
  • processing_for_distribution
  • ready_for_distribution
  • ready_for_review
  • rejected
  • replaced_with_new_version
  • waiting_for_export_compliance
  • waiting_for_review

on.app_store_connect.build_upload.states

Filters build upload events by state. Defaults to all supported build upload states when not provided.

Supported values:

  • complete
  • failed
  • processing
  • awaiting_upload

on.app_store_connect.external_beta.states

Filters external beta events by state. Defaults to all supported external beta states when not provided.

Supported values:

  • processing
  • processing_exception
  • missing_export_compliance
  • ready_for_beta_testing
  • in_beta_testing
  • expired
  • ready_for_beta_submission
  • in_export_compliance_review
  • waiting_for_beta_review
  • in_beta_review
  • beta_rejected
  • beta_approved

on.app_store_connect.beta_feedback.types

Filters beta feedback reported by testers by its type. Defaults to all supported beta feedback types when not provided.

Supported values:

  • crash
  • screenshot

All filter values must be lowercase and are case-sensitive.

# Triggers when: # - the app version enters review, # - a build upload completes or fails, # - an external beta build is ready for testing or approved, # - a tester reports a crash via TestFlight. on: app_store_connect: app_version: states: - ready_for_review - waiting_for_review build_upload: states: - complete - failed external_beta: states: - ready_for_beta_testing - beta_approved beta_feedback: types: - crash
# Triggers on any app version or build upload state change. on: app_store_connect: app_version: {} build_upload: {}

on.schedule.cron

Runs your workflow on a schedule using unix-cron syntax. You can use crontab guru and their examples to generate cron strings.

  • Scheduled workflows will only run on the default branch of the repository. In many cases, this means crons inside workflow files on the main branch will be scheduled, while crons inside workflow files in feature branches will not be scheduled.
  • Scheduled workflows may be delayed during periods of high load. High load times include the start of every hour. In rare circumstances, jobs may be skipped or run multiple times. Make sure that your workflows are idempotent and do not have harmful side effects.
  • A workflow can have multiple cron schedules.
  • Scheduled workflows run in the GMT time zone.
on: schedule: - cron: '0 0 * * *' # Runs at midnight GMT every day

on.workflow_dispatch.inputs

Defines inputs that can be provided when manually triggering a workflow using the eas workflow:run command. This allows you to create parameterized workflows that can accept different values each time they run.

on: workflow_dispatch: inputs: name: type: string required: false description: 'Name of the person to greet' default: 'World' choice_example: type: choice options: - to be - not to be required: true
PropertyTypeRequiredDescription
typestringThe input type (string, boolean, number, choice, or environment).
descriptionstringDescription for the input.
requiredbooleanWhether the input is required. Defaults to false.
defaultvariesDefault value for the input. Must match the input type.
optionsstring[] (for type: choice)Available options for choice inputs.

Providing inputs

When running a workflow with inputs, you can provide them in several ways:

  1. Command-line flags:

    Terminal
    - eas workflow:run .eas/workflows/deploy.yml -F environment=production -F debug=true -F version=1.2.3
  2. JSON via stdin:

    Terminal
    - echo '{"environment": "production", "debug": true, "version": "1.2.3"}' | eas workflow:run .eas/workflows/deploy.yml
  3. Interactive prompts: If required inputs are missing and you're not using --non-interactive, the CLI will prompt you for them:

    Terminal
    - eas workflow:run .eas/workflows/deploy.yml

Usage

Input values are available in your workflow jobs through the ${{ inputs.<input_name> }} syntax:

on: workflow_dispatch: inputs: name: type: string required: true description: 'Name of the person to greet' jobs: deploy: steps: - name: Deploy to environment run: | echo "Hello, ${{ inputs.name }}!" # Note: you can use `||` to provide a default value # for non-eas-workflow:run-run workflows. echo "Hello, ${{ inputs.name || 'World' }}!"

on.<trigger>.if

The if condition on a trigger decides whether a workflow run starts.

You can add if: under push, ref_delete, pull_request, pull_request_labeled, pull_request_comment, and each app_store_connect event domain (app_version, build_upload, external_beta, or beta_feedback).

The value is a boolean or an expression string. You can write it with or without the ${{ }} wrapper.

on: pull_request: if: ${{ !github.event.pull_request.draft }}

The expression must fit in one ${{ }} block and can be at most 250 characters.

When the condition evaluates to false, no workflow run starts for that trigger event. A retry of an existing run skips this check. It only applies when a new run is created.

The expression can use the github, app_store_connect, inputs, workflow, app, and account contexts. It supports all context functions except success(), failure(), and hashFiles(). Those functions need a job or step that has already run, but a trigger's if condition evaluates before any job starts.

on: push: if: ${{ github.ref_name == 'main' }} pull_request_comment: if: ${{ startsWith(github.event.comment.body, '/deploy') }}

jobs

A workflow run is made up of one or more jobs.

jobs: job_1: # ... job_2: # ...

jobs.<job_id>

Each job must have an ID. The ID should be unique within the workflow and can contain alphanumeric characters and underscores. For example, my_job in the following YAML:

jobs: my_job: # ...

jobs.<job_id>.name

The human-friendly name of the job displayed on the workflow's detail page.

jobs: my_job: name: Build app

jobs.<job_id>.environment

Sets the EAS environment variable environment for the job. There are three possible values:

  • production
  • preview
  • development

The environment key is available on all jobs. When you omit it, the default depends on the job type: build jobs infer it from the build profile's environment in eas.json, submit jobs inherit it from the submitted build, maestro and maestro-cloud jobs default to preview, and all other jobs default to production. See The job environment for details.

jobs: my_job: environment: production | preview | development

jobs.<job_id>.env

Sets environment variables for the job. The property is available on all jobs running a VM (all jobs except for the pre-packaged apple-device-registration-request, branch-delete, doc, get-build, github-comment, require-approval, slack, and update-rollout jobs).

jobs: my_job: env: APP_VARIANT: staging RETRY_COUNT: 3 PREV_JOB_OUTPUT: ${{ needs.previous_job.outputs.some_output }}

jobs.<job_id>.hooks

以下预置作业支持使用 hook,在主要作业操作之前或之后运行其他步骤:build、deploy、fingerprint、maestro、maestro-cloud、repack、submit、testflight 和 update。Hook 名称因作业而异。请参阅相应作业的文档,了解可用的 hook 键。要为 workflow 中的所有作业设置默认 hook,请使用 defaults.hooks。Hook 步骤可以像作业步骤一样调用自定义函数。

jobs: maestro_test: type: maestro-cloud params: build_id: ${{ needs.build.outputs.build_id }} maestro_project_id: proj_xyz flows: ./maestro/flows hooks: before_maestro_cloud: - run: echo "Before upload" after_maestro_cloud: - run: echo "After upload"

defaults.hooks

工作流中所有作业的默认 hook。每个作业会运行适用于自身的 hook 键,并忽略其余键。作业级别的 hook 键会覆盖 defaults.hooks 中的同名键。要让单个作业不使用默认 hook,请将该键设置为空数组。默认 hook 步骤也可以调用自定义函数。

defaults: hooks: before_install_node_modules: - name: Configure private registry run: echo "//npm.pkg.github.com/:_authToken=$GITHUB_TOKEN" >> .npmrc jobs: build_app: type: build params: platform: ios publish_update: type: update hooks: before_install_node_modules: [] # opt this job out of the default hook

defaults.image

Default VM image to use for all jobs in the workflow. Using an sdk-XX image tag is recommended. See Infrastructure for available images. Individual jobs can override this value with jobs.<job_id>.image.

defaults: image: sdk-57

defaults.run.working_directory

Default working directory to run the scripts in. Relative paths like "./assets" or "assets" are resolved from the app's base directory.

defaults.tools

Specific versions of tools that should be used for jobs defined in this workflow configuration. Follow each tool's documentation for available values.

ToolDescription
nodeVersion of Node.js installed via nvm.
yarnVersion of Yarn installed via npm -g.
corepackIf set to true, corepack will be enabled at the beginning of build process. Defaults to false.
pnpmVersion of pnpm installed via npm -g.
bunVersion of Bun installed by passing bun-v$VERSION to Bun install script.
ndkVersion of Android NDK installed through sdkmanager.
bundlerVersion of Bundler that will be passed to gem install -v.
fastlaneVersion of fastlane that will be passed to gem install -v.
cocoapodsVersion of CocoaPods that will be passed to gem install -v.

Example of workflow using defaults.tools:

.eas/workflows/publish-update.yml
name: Set up custom versions defaults: tools: node: latest yarn: '2' corepack: true pnpm: '8' bun: '1.0.0' fastlane: 2.224.0 cocoapods: 1.12.0 on: push: branches: ['*'] jobs: setup: steps: - name: Check Node version run: node --version # should print a concrete version, like 23.9.0 - name: Check Yarn version run: yarn --version # should print a concrete version, like 2.4.3

concurrency

Configuration for concurrency control. Currently only allows setting cancel_in_progress for same-branch workflows.

concurrency: cancel_in_progress: true group: ${{ workflow.filename }}-${{ github.ref }}
PropertyTypeDescription
cancel_in_progresstrueIf true, new workflow runs started from GitHub will cancel current in-progress runs for the same branch.
groupstringWe do not support custom concurrency groups yet. Set this placeholder value so that when we do support custom groups, your workflow remains compatible.

Control flow

You can control when a job runs with the needs and after keywords. In addition, you can use the if keyword to control whether a job should run based on a condition.

jobs.<job_id>.needs

A list of job IDs whose jobs must complete successfully before this job will run.

jobs: test: steps: - uses: eas/checkout - uses: eas/use_npm_token - uses: eas/install_node_modules - name: tsc run: yarn tsc build: needs: [test] # This job will only run if the 'test' job succeeds type: build params: platform: ios

jobs.<job_id>.after

A list of job IDs that must complete (successfully or not) before this job will run.

jobs: build: type: build params: platform: ios notify: after: [build] # This job will run after build completes (whether build succeeds or fails)

jobs.<job_id>.if

The if conditional determines if a job should run. When an if condition is met, the job will run. When the condition is not met, the job will be skipped. A skipped job won't have completed successfully and any downstream jobs will not run that have this job in their needs list.

jobs: my_job: if: ${{ github.ref_name == 'main' }}

Interpolation

You can customize the behavior of a workflow — commands to execute, control flow, environment variables, build profile, app version, and more — based on the workflow run's context.

Use the ${{ expression }} syntax to access context properties and functions. For example: ${{ github.ref_name }} or ${{ needs.build_ios.outputs.build_id }}.

Context properties

The following properties are available in interpolation contexts:

after

A record of all upstream jobs specified in the current job's after list. Each job provides:

{ "status": "success" | "failure" | "skipped", "outputs": {} }

Example:

jobs: build: type: build params: platform: ios notify: after: [build] steps: - run: echo "Build status: ${{ after.build.status }}"

needs

A record of all upstream jobs specified in the current job's needs list. Each job provides:

{ "status": "success" | "failure" | "skipped", "outputs": {} }

Most pre-packaged jobs expose specific outputs. You can set outputs in custom jobs using the set-output function.

Example:

jobs: setup: outputs: date: ${{ steps.current_date.outputs.date }} steps: - id: current_date run: | DATE=$(date +"%Y.%-m.%-d") set-output date "$DATE" build_ios: needs: [setup] type: build env: # You might use process.env.VERSION_SUFFIX to customize # app version in your dynamic app config. VERSION_SUFFIX: ${{ needs.setup.outputs.date }} params: platform: ios profile: development

steps

A record of all steps in the current job. Each step provides its outputs set using the set-output function.

Example:

jobs: my_job: outputs: value: ${{ steps.step_1.outputs.value }} steps: - id: step_1 run: set-output value "hello" - run: echo ${{ steps.step_1.outputs.value }} another_job: needs: [my_job] steps: - run: echo "Value: ${{ needs.my_job.outputs.value }}"

inputs

A record of inputs provided when manually triggering a workflow with workflow_dispatch. Available when the workflow is triggered via eas workflow:run command with input parameters.

Example:

on: workflow_dispatch: inputs: name: type: string required: true jobs: greet: steps: - run: echo "Hello, ${{ inputs.name }}!"

github

To ease the migration from GitHub Actions to EAS Workflows we expose some context fields you may find useful.

type GitHubContext = { triggering_actor?: string; event_name: 'pull_request' | 'push' | 'schedule' | 'workflow_dispatch'; sha: string; ref: string; // e.g. refs/heads/main ref_name: string; // e.g. main ref_type: 'branch' | 'tag' | 'other'; commit_message?: string; // Only available for push and schedule events label?: string; repository?: string; repository_owner?: string; event?: { action?: string; label?: { name: string; }; // Only available for push and schedule events head_commit?: { message: string; id: string; }; pull_request?: { number: number; title: string; body: string | null; state: 'open' | 'closed'; draft: boolean; merged: boolean | null; // ... Other fields from the GitHub Pull Request webhook payload }; comment?: { body: string; // ... Other fields from the GitHub issue_comment webhook payload }; changes?: { base?: { ref?: { from: string; }; }; }; number?: number; schedule?: string; inputs?: Record<string, string | number | boolean>; }; };

If a workflow run is started from eas workflow:run, its event_name will be workflow_dispatch and all the rest of the properties will be empty.

Example:

jobs: build_ios: type: build if: ${{ github.ref_name == 'main' }} params: platform: ios profile: production
${{ github }} context

View the ${{ github }} definition source code.

workflow

Information about the current workflow.

type WorkflowContext = { id: string; name: string; filename: string; url: string; };

Example:

jobs: notify_slack: after: [...] type: slack params: message: | Workflow run completed: ${{ workflow.name }} View details: ${{ workflow.url }}

app

Information about the EAS project the workflow runs for. This context is available in every workflow run.

type AppContext = { id: string; slug: string; };

Example:

jobs: print_context: steps: - run: echo "Project ${{ app.slug }} (${{ app.id }})"

account

Information about the account that owns the project. This context is available in every workflow run.

type AccountContext = { id: string; name: string; };

Example:

jobs: print_context: steps: - run: echo "Account ${{ account.name }} (${{ account.id }})"

app_store_connect

Information about App Store Connect entities associated with the workflow run. This context is available only for workflows triggered by an App Store Connect event. See on.app_store_connect.

type AppStoreConnectContext = { app: { id: string; }; build_upload?: { id: string; state: 'awaiting_upload' | 'processing' | 'failed' | 'complete'; cf_bundle_version?: string; cf_bundle_short_version_string?: string; platform?: string; uploaded_date?: string; created_date?: string; build?: { id: string; }; }; app_version?: { id: string; state: string; }; external_beta?: { id: string; state: string; }; beta_feedback?: { id: string; type: 'crash' | 'screenshot'; url: string; }; };

The app_store_connect.build_upload object is present only when the workflow is triggered by a build_upload event domain.

Example:

on: app_store_connect: build_upload: states: - complete jobs: notify: type: slack params: webhook_url: ${{ env.SLACK_WEBHOOK_URL }} message: | Upload complete for App Store Connect app: ${{ app_store_connect.app.id }} Upload ID: ${{ app_store_connect.build_upload.id }} Upload state: ${{ app_store_connect.build_upload.state }} Version: ${{ app_store_connect.build_upload.cf_bundle_short_version_string }} (${{ app_store_connect.build_upload.cf_bundle_version }})

Use build_upload.build.id as the asc_build_id for a testflight job:

.eas/workflows/testflight-after-asc-upload.yml
name: Distribute to TestFlight after ASC upload on: app_store_connect: build_upload: states: - complete jobs: distribute_to_testflight: name: Distribute to TestFlight type: testflight params: asc_build_id: ${{ app_store_connect.build_upload.build.id }} internal_groups: - QA Team external_groups: - Public Beta changelog: | Build ${{ app_store_connect.build_upload.cf_bundle_version }} is ready for testing. submit_beta_review: true

env

A record of environment variables available in the current job context.

Example:

jobs: my_job: steps: - run: echo "API URL: ${{ env.API_URL }}"

Context functions

The following functions are available in interpolation contexts:

success()

Returns whether all previous jobs have succeeded.

jobs: notify: if: ${{ success() }} steps: - run: echo "All jobs succeeded"

failure()

Returns whether any previous job has failed.

jobs: notify: if: ${{ failure() }} steps: - run: echo "A job failed"

fromJSON(value)

Parses a JSON string. Equivalent to JSON.parse().

Example:

jobs: publish_update: type: update print_debug_info: needs: [publish_update] steps: - run: | echo "First update group: ${{ needs.publish_update.outputs.first_update_group_id }}" echo "Second update group: ${{ fromJSON(needs.publish_update.outputs.updates_json || '[]')[1].group }}"

toJSON(value)

Converts a value to a JSON string. Equivalent to JSON.stringify().

Example:

jobs: my_job: steps: - run: echo '${{ toJSON(github.event) }}'

contains(value, substring)

Checks whether value contains substring.

Example:

jobs: my_job: if: ${{ contains(github.ref_name, 'feature') }} steps: - run: echo "Feature branch"

startsWith(value, prefix)

Checks whether value starts with prefix.

Example:

jobs: my_job: if: ${{ startsWith(github.ref_name, 'release') }} steps: - run: echo "Release branch"

endsWith(value, suffix)

Checks whether value ends with suffix.

Example:

jobs: my_job: if: ${{ endsWith(github.ref_name, '-production') }} steps: - run: echo "Production branch"

hashFiles(...globs)

Returns a hash of files matching the provided glob patterns. Useful for cache keys.

Example:

jobs: my_job: steps: - run: echo "Dependencies hash: ${{ hashFiles('package-lock.json', 'yarn.lock') }}"

replaceAll(input, stringToReplace, replacementString)

Replaces all occurrences of stringToReplace in input with replacementString.

Example:

jobs: my_job: steps: - run: echo "${{ replaceAll(github.ref_name, '/', '-') }}"

substring(input, start, end)

Extracts a substring from input starting at start and ending at end. If end is not provided, the substring is extracted from start to the end of input. Uses String#substring under the hood.

Example:

jobs: my_job: steps: - run: echo "${{ substring(github.ref_name, 0, 50) }}"

Pre-packaged jobs

jobs.<job_id>.type

Specifies the type of pre-packaged job to run. Pre-packaged jobs produce specialized UI according to the type of job on the workflow's detail page.

jobs: my_job: type: build

Learn about the different pre-packaged jobs below.

build

Creates an Android or iOS build of your project using EAS Build. See Build job documentation for detailed information and examples.

jobs: my_job: type: build params: platform: ios | android # required profile: string # optional, default: production message: string # optional refresh_ad_hoc_provisioning_profile: boolean # optional hooks: before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional

This job outputs the following properties:

{ "build_id": string, "app_build_version": string | null, "app_identifier": string | null, "app_version": string | null, "channel": string | null, "distribution": "internal" | "store" | null, "fingerprint_hash": string | null, "git_commit_hash": string | null, "platform": "ios" | "android" | null, "profile": string | null, "runtime_version": string | null, "sdk_version": string | null, "simulator": "true" | "false" | null }

deploy

Deploys your application using EAS Hosting. See Deploy job documentation for detailed information and examples.

jobs: my_job: type: deploy params: alias: string # optional prod: boolean # optional source_maps: boolean # optional hooks: after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional

This job outputs the following properties:

{ "deploy_json": string, // JSON object containing the deployment details (output of `npx eas-cli deploy --json`). "deploy_url": string, // URL to the deployment. It uses production URL if this was a production deployment. Otherwise, it uses the first alias URL or the deployment URL. "deploy_alias_url": string, // Alias URL to the deployment (for example, `https://account-project--alias.expo.app`). "deploy_deployment_url": string, // Unique URL to the deployment (for example, `https://account-project--uniqueid.expo.app`). "deploy_identifier": string, // Identifier of the deployment. "deploy_dashboard_url": string, // URL to the deployment dashboard (for example, `https://expo.dev/projects/[project]/hosting/deployments`). }

fingerprint

Calculates a fingerprint of your project. See Fingerprint job documentation for detailed information and examples.

jobs: my_job: type: fingerprint environment: production # Should match your build profile hooks: after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional

This job outputs the following properties:

{ "android_fingerprint_hash": string, "ios_fingerprint_hash": string, }

get-build

Retrieves an existing build from EAS that matches the provided parameters. See Get Build job documentation for detailed information and examples.

jobs: my_job: type: get-build params: platform: ios | android # optional profile: string # optional distribution: store | internal | simulator # optional channel: string # optional app_identifier: string # optional app_build_version: string # optional app_version: string # optional git_commit_hash: string # optional fingerprint_hash: string # optional sdk_version: string # optional runtime_version: string # optional simulator: boolean # optional wait_for_in_progress: boolean # optional

This job outputs the following properties:

{ "build_id": string, "app_build_version": string | null, "app_identifier": string | null, "app_version": string | null, "channel": string | null, "distribution": "internal" | "store" | null, "fingerprint_hash": string | null, "git_commit_hash": string | null, "platform": "ios" | "android" | null, "profile": string | null, "runtime_version": string | null, "sdk_version": string | null, "simulator": "true" | "false" | null }

submit

Submits an Android or iOS build to the app store using EAS Submit. See Submit job documentation for detailed information and examples.

jobs: my_job: type: submit params: build_id: string # required profile: string # optional, default: production groups: string[] # optional hooks: after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional before_submit: step[] # optional after_submit: step[] # optional

This job outputs the following properties:

{ "apple_app_id": string | null, // Apple App ID. https://expo.fyi/asc-app-id "ios_bundle_identifier": string | null, // iOS bundle identifier of the submitted build. https://expo.fyi/bundle-identifier "android_package_id": string | null // Submitted Android package ID. https://expo.fyi/android-package }

testflight

Distributes iOS builds to TestFlight internal and external testing groups. Provide exactly one of build_id (upload a build and submit to TestFlight) or asc_build_id (submit an already uploaded build). See TestFlight job documentation for detailed information and examples.

jobs: my_job: type: testflight params: build_id: string # required to upload and submit to TestFlight; mutually exclusive with asc_build_id profile: string # optional, default: production; only when uploading and submitting wait_processing_timeout_seconds: number # optional, default: 1800 (30 minutes); only when uploading and submitting in one job asc_build_id: string # required to submit an already uploaded build; mutually exclusive with build_id internal_groups: string[] # optional external_groups: string[] # optional changelog: string # optional submit_beta_review: boolean # optional hooks: # only when uploading and submitting with build_id after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional

This job outputs the following properties, where asc_build_id is only set when submitting an already uploaded build:

{ "apple_app_id": string | null, // Apple App ID. https://expo.fyi/asc-app-id "ios_bundle_identifier": string | null, // iOS bundle identifier of the submitted build. https://expo.fyi/bundle-identifier "asc_build_id": string | null // App Store Connect build ID. Only when submitting an already uploaded build. }

update

Publishes an update using EAS Update. See Update job documentation for detailed information and examples.

jobs: my_job: type: update params: message: string # optional platform: string # optional - android | ios | all, defaults to all branch: string # optional channel: string # optional - cannot be used with branch rollout_percentage: number # optional - 0 to 100, defaults to 100 private_key_path: string # optional upload_sentry_sourcemaps: boolean # optional - defaults to "try uploading, but don't fail the job if it fails" hooks: after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional before_update: step[] # optional after_update: step[] # optional

This job outputs the following properties:

{ "first_update_group_id": string, // ID of the first update group. You can use it to e.g. construct the update URL for a development client deep link. "updates_json": string // Stringified JSON array of update groups. Output of `eas update --json`. }

update-rollout

Increases the rollout percentage of an in-progress EAS Update rollout. See Update rollout job documentation for detailed information and examples.

jobs: my_job: type: update-rollout params: update_group_id: string # required rollout_percentage: number # optional - 0 to 100, defaults to 100

This job outputs the following properties:

{ "update_group_id": string, // ID of the update group that was rolled out. "rollout_percentage": string, // The rollout percentage that was applied to the update group. "updates_json": string // Stringified JSON array of the updates in the group. }

branch-delete

Deletes an EAS Update branch and all of its updates. See Branch delete job documentation for detailed information and examples.

jobs: my_job: type: branch-delete params: branch_name: string # required fail_on_missing: boolean # optional, default: false

This job outputs the following properties:

{ "branch_id": string | null, "branch_name": string }

maestro

Runs Maestro tests on a build. See Maestro job documentation for detailed information and examples.

jobs: my_job: type: maestro environment: production | preview | development # optional, defaults to preview image: string # optional. See https://docs.expo.dev/build-reference/infrastructure/ for a list of available images. runs_on: string # optional. Use a linux-*-nested-virtualization worker for Android Emulator tests. See https://docs.expo.dev/eas/workflows/syntax/#jobsjob_idruns_on for available options. params: build_id: string # required flow_path: string | string[] # required shards: number # optional, defaults to 1 retries: number # optional, defaults to 0 retry_failed_only: boolean # optional, defaults to true. When true, retries will attempt to re-run only the flows that failed on the previous attempt when applicable. record_screen: boolean # optional, defaults to false. If true, uploads a screen recording of the tests. include_tags: string | string[] # optional. Tags to include in the tests. Will be passed to Maestro as `--include-tags`. exclude_tags: string | string[] # optional. Tags to exclude from the tests. Will be passed to Maestro as `--exclude-tags`. maestro_version: string # optional. Version of Maestro to use for the tests. If not provided, the latest version will be used. android_system_image_package: string # optional. Android Emulator system image package to use. device_identifier: string | { android?: string, ios?: string } # optional. Device identifier to use for the tests. output_format: string # optional, defaults to junit. Maestro test report format. Will be passed to Maestro as `--format`. Can be `junit` or other supported formats. skip_build_check: boolean # optional, defaults to false. Skip validation of the build (whether an iOS build is a simulator build). hooks: after_checkout: step[] # optional before_maestro_tests: step[] # optional after_maestro_tests: step[] # optional

maestro-cloud

Runs Maestro tests on a build in Maestro Cloud. See Maestro Cloud job documentation for detailed information and examples.

jobs: my_job: type: maestro-cloud environment: production | preview | development # optional, defaults to preview image: string # optional. See https://docs.expo.dev/build-reference/infrastructure/ for a list of available images. params: build_id: string # required. ID of the build to test. maestro_project_id: string # required. Maestro Cloud project ID. Example: `proj_01jw6hxgmdffrbye9fqn0pyzm0`. flows: string # required. Path to the Maestro flow file or directory containing the flows to run. Corresponds to `--flows` param to `maestro cloud`. maestro_api_key: string # optional. The API key to use for the Maestro project. By default, `MAESTRO_CLOUD_API_KEY` environment variable will be used. Corresponds to `--api-key` param to `maestro cloud`. include_tags: string | string[] # optional. Tags to include in the tests. Will be passed to Maestro as `--include-tags`. exclude_tags: string | string[] # optional. Tags to exclude from the tests. Will be passed to Maestro as `--exclude-tags`. maestro_version: string # optional. Version of Maestro to use for the tests. If not provided, the latest version will be used. maestro_config: string # optional. Path to the Maestro `config.yaml` file to use for the tests. Will be passed to Maestro as `--config`. device_locale: string # optional. Device locale to use for the tests. Will be passed to Maestro as `--device-locale`. device_model: string # optional. Model of the device to use for the tests. Will be passed to Maestro as `--device-model`. Run `maestro list-cloud-devices` for a list of supported values. device_os: string # optional. OS of the device to use for the tests. Will be passed to Maestro as `--device-os`. Run `maestro list-cloud-devices` for a list of supported values. skip_build_check: boolean # optional, defaults to false. Skip validation of the build (whether an iOS build is a simulator build). name: string # optional. Name for the Maestro Cloud upload. Corresponds to `--name` param to `maestro cloud`. branch: string # optional. Override for the branch the Maestro Cloud upload originated from. By default, if the workflow run has been triggered from GitHub, the branch of the workflow run will be used. Corresponds to `--branch` param to `maestro cloud`. async: boolean # optional. Run the Maestro Cloud tests asynchronously. If true, the status of the job will only denote whether the upload was successful, *not* whether the tests succeeded. Corresponds to `--async` param to `maestro cloud`. hooks: after_checkout: step[] # optional. Steps to run after the job checks out your project. before_maestro_cloud: step[] # optional. Steps to run before the Maestro Cloud upload. after_maestro_cloud: step[] # optional. Steps to run after the Maestro Cloud upload.

slack

Sends a message to a Slack channel using a webhook URL. See Slack job documentation for detailed information and examples.

jobs: my_job: type: slack params: webhook_url: string # required message: string # required if payload is not provided payload: object # required if message is not provided

github-comment

Automatically posts comprehensive reports of your workflow's completed builds, updates, and deployments to GitHub pull requests or content provided by you. See GitHub Comment job documentation for detailed information and examples.

jobs: my_job: type: github-comment params: message: string # optional - custom message to include in the report build_ids: string[] # optional - specific build IDs to include, defaults to all related to the running workflow update_group_ids: string[] # optional - specific update group IDs to include, defaults to all related to the workflow deployment_ids: string[] # optional - specific deployment IDs to include, defaults to all related to the workflow # instead of using message and the builds, updates, and deployments table, you can also override the comment contents with `payload` custom_github_comment: type: github-comment params: payload: string # optional - raw markdown/HTML content for fully custom comment

This job outputs the following properties:

{ "comment_url": string | undefined // URL of the posted GitHub comment }

apple-device-registration-request

Pauses the workflow until an iOS device enrolls for an Apple team and a team member approves the enrollment. See Apple device registration request job documentation for detailed information and examples.

jobs: register_device: type: apple-device-registration-request params: apple_team_identifier: string # optional

require-approval

Requires approval from a user before continuing with the workflow. A user can approve or reject which translates to success or failure of the job. See Require Approval job documentation for detailed information and examples.

jobs: confirm: type: require-approval

doc

Displays a Markdown section in the workflow logs. See Doc job documentation for detailed information and examples.

jobs: next_steps: type: doc params: md: string

repack

Repackages an app from an existing build. This job repackages the app's metadata and JavaScript bundle without performing a full native rebuild, which is useful for creating a faster build compatible with a specific fingerprint. See Repack job documentation for detailed information and examples.

jobs: next_steps: type: repack params: build_id: string # required profile: string # optional embed_bundle_assets: boolean # optional js_bundle_only: boolean # optional ios_signing_use_source_app_entitlements: boolean # optional ios_signing_app_entitlements_path: string # optional message: string # optional repack_version: string # optional repack_package: string # optional hooks: after_checkout: step[] # optional before_install_node_modules: step[] # optional after_install_node_modules: step[] # optional

Custom jobs

Runs custom code and can use built-in EAS functions. Does not require a type field.

jobs: my_job: steps: # ...

jobs.<job_id>.steps

A job contains a sequence of tasks called steps. Steps can run commands. steps may only be provided in custom jobs and build jobs.

jobs: my_job: steps: - name: My first step run: echo "Hello World"

jobs.<job_id>.outputs

A list of outputs defined by the job. These outputs are accessible to all downstream jobs that depend on this job. To set outputs, use the set-output function within a job step.

Downstream jobs can access these outputs using the following expressions within interpolation contexts:

  • needs.<job_id>.outputs.<output_name>
  • after.<job_id>.outputs.<output_name>

Here, <job_id> refers to the identifier of the upstream job, and <output_name> refers to the specific output variable you want to access.

In the example below, the set-output function sets the output named test to the value hello world in job_1's step_1 step. Later in job_2, it's accessed in step_2 using needs.job_1.outputs.output_1.

jobs: job_1: outputs: output_1: ${{ steps.step_1.outputs.test }} steps: - id: step_1 run: set-output test "hello world" job_2: needs: [job_1] steps: - id: step_2 run: echo ${{ needs.job_1.outputs.output_1 }}

jobs.<job_id>.image

Specifies the VM image to use for the job. See Infrastructure for available images.

jobs: my_job: image: auto | string # optional, defaults to 'auto'

jobs.<job_id>.runs_on

Specifies the worker that will execute the job. Available on custom jobs and on the build, maestro, maestro-cloud, and repack pre-packaged jobs.

jobs: my_job: runs_on: linux-medium | linux-large | linux-medium-nested-virtualization | linux-large-nested-virtualization | macos-medium | macos-large # optional, defaults to linux-medium
工作器vCPU内存(GiB RAM)SSD(GiB)备注
linux-medium41614默认工作器。
linux-large83228
linux-medium-nested-virtualization41614允许运行 Android 模拟器。
linux-large-nested-virtualization43228允许运行 Android 模拟器。
工作器效率核心数统一内存(GiB RAM)SSD(GiB)备注
macos-medium520125运行 iOS 作业,包括模拟器。
macos-large1040125运行 iOS 作业,包括模拟器。

jobs.<job_id>.steps.<step>.id

id 属性用于在作业中引用该步骤。可用于在下游作业中使用该步骤的输出。

jobs: my_job: outputs: test: ${{ steps.step_1.outputs.test }} # 引用 step_1 的输出 steps: - id: step_1 run: set-output test "hello world"

jobs.<job_id>.steps.<step>.name

该步骤的人类可读名称,会显示在作业日志中。当步骤未提供名称时,会使用 run 命令作为步骤名称。

jobs: my_job: steps: - name: 我的第一步 run: echo "Hello World"

jobs.<job_id>.steps.<step>.run

在该步骤中运行的 shell 命令。

jobs: my_job: steps: - run: echo "Hello World"

jobs.<job_id>.steps.<step>.shell

Shell 用于运行命令。默认值为 bash。

jobs: my_job: steps: - run: echo "Hello World" shell: bash

jobs.<job_id>.steps.<step>.working_directory

运行命令的目录。当在步骤级别定义时,如果作业中也定义了 jobs.<job_id>.defaults.run.working_directory 设置,则该设置会被覆盖。

jobs: my_job: steps: - uses: eas/checkout - run: pwd # 输出:/home/expo/workingdir/build/my-app working_directory: ./my-app

jobs.<job_id>.steps.<step>.uses

EAS 提供了一组内置的可复用函数,可在工作流步骤中使用。uses 关键字用于指定要使用的函数。所有内置函数都以 eas/ 前缀开头。

jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/prebuild - name: 列出文件 run: ls -la

你可以在项目中定义可复用的步骤序列,并使用以 ./ 或 ../ 开头的路径调用它们,例如 ./.eas/functions/setup。请参阅自定义函数 schema以及在 EAS Workflows 中使用自定义函数指南。

以下是可以在工作流步骤中使用的内置函数列表。

eas/checkout

检出你的项目源文件。

jobs: my_job: steps: - uses: eas/checkout

对于使用基于 Git 的项目源的作业,该步骤默认使用作业记录的提交。使用 ref 可以检出其他分支、标签或提交:

jobs: my_job: steps: - uses: eas/checkout with: ref: feature/add-icon

ref 接受以下内容:

  • 分支,可以是 feature/add-icon 这样的裸名称,也可以是 refs/heads/feature/add-icon 这样的限定引用。仓库最终会位于该分支上。
  • 标签,例如 refs/tags/v1.2.3 这样的限定引用。仓库最终会处于分离的 HEAD 状态。
  • 完整的提交 SHA。仓库最终会处于分离的 HEAD 状态。

该步骤会从源仓库的 origin 执行浅层提取(--depth 1),因此该引用必须在那里可访问。

ref 仅在项目源来自 Git 仓库时有效,例如通过 GitHub 集成触发的作业。本地构建和上传的项目 tarball 不支持此功能。请在作业的第一个 eas/checkout 步骤中设置 ref。在后续步骤中设置会失败,因为项目已经检出。

属性类型必填描述
refstring要检出的 Git 分支、标签或完整提交 SHA。默认为触发构建或工作流任务的 ref。
eas/checkout 源代码

在 GitHub 上查看 eas/checkout 函数的源代码。

eas/install_node_modules

使用根据你的项目检测到的包管理器(bun、npm、pnpm 或 Yarn)安装 node_modules。适用于 monorepo。

example.yml
jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules
eas/install_node_modules 源代码

在 GitHub 上查看 eas/install_node_modules 函数的源代码。

eas/download_build

下载给定构建的应用归档。默认情况下,下载的产物可以是 .apk、.aab、.ipa 或 .app 文件,或者是一个包含这些文件中一个或多个的 .tar.gz 归档。如果产物是 .tar.gz 归档,它将被解压,并返回匹配指定扩展名的第一个文件。如果构建未生成任何应用归档,该步骤将失败。

jobs: my_job: steps: - uses: eas/download_build with: build_id: string # 必填。要下载的构建 ID。 extensions: [apk, aab, ipa, app] # 可选。要查找的文件扩展名列表。默认为 ["apk", "aab", "ipa", "app"]。
属性类型必填默认值描述
build_idstring–要下载的构建的 ID。必须是有效的 UUID。
extensionsstring[]["apk", "aab", "ipa", "app"]要在下载的工件或存档中查找的文件扩展名列表。
输出
属性类型描述
artifact_pathstring匹配的应用程序存档的绝对路径。此输出可用作其他步骤的输入。例如,可用于上传或进一步处理工件。
eas/download_build 源代码

在 GitHub 上查看 eas/download_build 函数的源代码。

示例用法:

jobs: build_ios: type: build params: platform: ios profile: production my_job: needs: [build_ios] steps: - uses: eas/download_build id: download_build with: build_id: ${{ needs.build_ios.outputs.build_id }} - name: 打印产物路径 run: | echo "Artifact path: ${{ steps.download_build.outputs.artifact_path }}"

eas/prebuild

使用根据你的项目检测到的包管理器(bun、npm、pnpm 或 Yarn),并采用最适合你的构建类型和构建环境的命令来运行 expo prebuild 命令。

jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/prebuild
jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/resolve_apple_team_id_from_credentials id: resolve_apple_team_id_from_credentials - uses: eas/prebuild with: clean: false apple_team_id: ${{ steps.resolve_apple_team_id_from_credentials.outputs.apple_team_id }}
属性类型描述
cleanboolean可选属性,用于定义函数运行命令时是否应使用 --clean 标志。默认为 false。
apple_team_idstring可选属性,用于定义执行预构建时应使用的 Apple 团队 ID。使用凭据进行 iOS 构建时必须指定此属性。
eas/prebuild 源代码

在 GitHub 上查看 eas/prebuild 函数的源代码。

eas/restore_cache

从指定键恢复之前保存的缓存。这对于通过重用已缓存的产物(如已编译的依赖项、构建工具或其他中间构建输出)来加快构建速度很有用。

jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/prebuild - uses: eas/restore_cache with: key: cache-${{ hashFiles('package-lock.json') }} restore_keys: cache path: /path/to/cache
jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/prebuild - uses: eas/restore_cache with: key: cache-${{ hashFiles('package-lock.json') }} path: /path/to/cache
属性类型必填描述
keystring要恢复的缓存键。您可以使用 ${{ hashFiles('package-lock.json') }} 等表达式,根据文件哈希创建动态键。
restore_keysstring如果未找到完全匹配的键,则使用的备用键或前缀。如果提供了该值,缓存系统将查找所有以此前缀开头的缓存条目。
pathstring缓存应恢复到的路径。该路径应与保存缓存时使用的路径一致。
eas/restore_cache 源代码

在 GitHub 上查看 eas/restore_cache 函数的源代码。

eas/save_cache

将缓存保存到指定键。这使你可以持久化构建产物、已编译的依赖项或其他中间输出,以便在后续构建中重复使用,从而加快构建过程。

jobs: my_job: steps: - uses: eas/checkout - uses: eas/install_node_modules - uses: eas/prebuild - uses: eas/restore_cache with: key: cache-${{ hashFiles('package-lock.json') }} path: /path/to/cache - name: 构建 Android 应用 run: cd android && ./gradlew assembleRelease - uses: eas/save_cache with: key: cache-${{ hashFiles('package-lock.json') }} path: /path/to/cache
属性类型必填描述
keystring保存缓存所使用的缓存键。你可以使用 ${{ hashFiles('package-lock.json') }} 这样的表达式,根据文件哈希创建动态键。此键应与恢复缓存时使用的键一致。
pathstring应缓存的目录或文件的路径。此路径应与恢复缓存时使用的路径一致。
eas/save_cache 源代码

在 GitHub 上查看 eas/save_cache 函数的源代码。

eas/send_slack_message

向已配置的 Slack webhook URL 发送指定消息,然后它会将消息发布到相关的 Slack 频道。消息可以指定为纯文本或 Slack Block Kit 消息。

你可以在消息中引用构建作业属性,并使用其他步骤的输出进行动态求值。例如,Build URL: https://expo.dev/builds/${{ needs.build_ios.outputs.build_id }}、Build finished with status: ${{ after.build_android.status }}。

必须指定 message 或 payload 其中之一,但不能同时指定两者。

jobs: my_job: steps: - uses: eas/send_slack_message with: message: 'This is a message sent to a Slack channel' slack_hook_url: ${{ env.ANOTHER_SLACK_HOOK_URL }}
PropertyTypeDescription
messagestring要发送的消息文本。例如,'This is the content of the message'。

**注意:**必须提供 message 或 payload,但不能同时提供两者。
payloadjson要发送的消息内容,使用 Slack Block Kit 布局定义。

**注意:**必须提供 message 或 payload,但不能同时提供两者。
slack_hook_urlstring之前配置的 Slack webhook URL,该 URL 会将你的消息发布到指定频道。请使用 EAS 环境变量 提供,例如 slack_hook_url: ${{ env.ANOTHER_SLACK_HOOK_URL }};或者设置 SLACK_HOOK_URL 环境变量,该变量将作为默认 webhook URL(在后一种情况下,无需提供 slack_hook_url 属性)。
eas/send_slack_message 源代码

在 GitHub 上查看 eas/send_slack_message 函数的源代码。

eas/use_npm_token

配置 Node 包管理器(bun、npm、pnpm 或 Yarn)以便与私有包一起使用,这些包可以发布到 npm 或私有注册表。

在项目的 secrets 中设置 NPM_TOKEN,该函数将通过使用该令牌创建 .npmrc 来配置构建环境。

example.yml
jobs: my_job: name: 安装私有 npm 模块 steps: - uses: eas/checkout - uses: eas/use_npm_token - name: 安装依赖 run: npm install # <---- 现在可以安装私有包了
eas/use_npm_token 源代码

在 GitHub 上查看 eas/use_npm_token 函数的源代码。

eas/upload_artifact

将作业工作区中的文件作为附加到工作流运行的工件上传。上传的工件会显示在运行的 Artifacts 部分,并可在后续作业中通过 eas/download_artifact 获取。

jobs: my_job: steps: - uses: eas/checkout - name: Run tests run: ./scripts/run-tests.sh # 将结果写入 ./results - uses: eas/upload_artifact if: ${{ always() }} with: type: other name: test-results path: | results/**/*
属性
属性类型必填描述
pathstring要上传的路径或以换行符分隔的路径列表。支持 * 和其他 glob 模式。
typestring构件类型。在自定义作业中使用 other(通用构件)。当作业没有构建平台时,默认为 other;在构建作业中默认为 application-archive。构建范围的值 application-archive 和 build-artifact 仅适用于构建作业。
namestring构件名称,用于从 eas/download_artifact 引用该构件。
metadatajson要附加到通用(other)构件的任意元数据。
ignore_errorboolean为 true 时,上传失败会记录日志,但不会导致步骤失败。默认为 false。
输出
属性类型描述
artifact_idstring已上传构件的 ID。可传递给 eas/download_artifact。
eas/upload_artifact 源代码

在 GitHub 上查看 eas/upload_artifact 函数的源代码。

eas/download_artifact

根据工件的 ID 或名称从 EAS 下载一个工件。适用于将前面作业中的工件发送到其他服务。

jobs: my_job: steps: - uses: eas/download_artifact with: name: string # 如果未提供 artifact_id,则为必填。要下载的工件名称。 artifact_id: string # 如果未提供 artifact_name,则为必填。要下载的工件 ID。
属性
属性类型必填描述
namestring要下载的构建产物名称。如果未提供 artifact_id,则此项为必填项。
artifact_idstring要下载的构建产物 ID。如果未提供 name,则此项为必填项。
输出
属性类型描述
artifact_pathstring已下载构建产物的路径。此输出可用作工作流中其他步骤的输入。例如,用于发送或处理构建产物。
eas/download_artifact 源代码

在 GitHub 上查看 eas/download_artifact 函数的源代码。

示例
jobs: maestro_tests: type: maestro params: build_id: '123-abc' flow_path: 'path/to/flow.yaml' my_job: needs: [maestro_tests] steps: - uses: eas/download_artifact id: download_artifact with: name: 'iOS Maestro Test Report (junit)' - name: 打印 Maestro 输出 run: echo ${{ steps.download_artifact.outputs.artifact_path }}

以下函数可将你的工作流连接到 PostHog。运行 eas integrations:posthog:connect 以关联 PostHog 项目,并设置这些函数读取的环境变量。eas/posthog_capture_event 使用你的公共项目 API 密钥,而其他函数使用 PostHog 个人 API 密钥,并要求具备各函数注明的权限范围。有关设置,请参阅使用 PostHog;有关完整工作流,请参阅 EAS Workflows 的 PostHog 配方。

eas/posthog_capture_event

向 PostHog 发送分析事件。你可以使用它在 PostHog 时间线中标记构建、发布和其他里程碑。

如果不提供 distinct_id,事件将以匿名方式发送,并且不会创建 PostHog 人员档案,从而使工作流事件不会出现在人员列表中。

jobs: my_job: steps: - uses: eas/posthog_capture_event with: event: ota_update_published properties: branch: main
属性
属性类型必填描述
eventstring要发送的事件名称。
distinct_idstring要将事件归因到的人员。省略时,事件将匿名发送,且不会创建人员档案。
propertiesjson要附加到事件的属性。
api_keystringPostHog 项目 API 密钥。默认为由 eas integrations:posthog:connect 设置的 EXPO_PUBLIC_POSTHOG_API_KEY 环境变量;如果未设置,则回退到 POSTHOG_API_KEY。
hoststringPostHog 主机。默认为 EXPO_PUBLIC_POSTHOG_HOST 环境变量,或 https://us.posthog.com。
ignore_errorboolean当值为 true 时,发送事件失败会记录日志,但不会导致步骤失败。默认为 false。
eas/posthog_capture_event 源代码

在 GitHub 上查看 eas/posthog_capture_event 函数的源代码。

eas/posthog_flag_rollout

启用、禁用或逐步发布 PostHog 功能标志。该函数会通过键查找标志,然后更新它。至少提供 active、rollout_percentage 或 payload 其中之一。

jobs: my_job: steps: - uses: eas/posthog_flag_rollout with: flag: new-checkout rollout_percentage: 25
属性
PropertyTypeRequiredDescription
flagstring要更新的功能标志键。
activeboolean功能标志是否已启用。
rollout_percentagenumber功能标志面向的用户百分比,取值为 0 到 100 之间的整数。此函数会将其应用于功能标志的兜底发布条件,并保留其他条件。如果功能标志没有兜底条件,此函数会将其应用于第一个条件。
payloadjson要附加到功能标志的负载。
variantstring在多变量功能标志上用于存储 payload 的变体键。默认为功能标志的 true 负载。
api_keystringPostHog 个人 API 密钥。默认为 POSTHOG_CLI_API_KEY 环境变量。需要 feature_flag:read 和 feature_flag:write 作用域。
project_idstringPostHog 项目 ID。默认为 POSTHOG_CLI_PROJECT_ID 环境变量。
ignore_errorboolean为 true 时,网络错误、缺少功能标志或意外响应会被记录,但不会导致步骤失败。默认为 false。权限错误或无效输入(例如超出范围的 rollout_percentage)始终会导致步骤失败。
eas/posthog_flag_rollout 源代码

在 GitHub 上查看 eas/posthog_flag_rollout 函数的源代码。

eas/posthog_wait_for_metric

暂停工作流,直到 HogQL 查询返回满足比较条件的数值。你可以使用它根据某项指标控制发布流程,例如等待最近几分钟的错误数保持较低。

该函数每隔 interval_seconds 运行一次查询,直到比较结果为真或 timeout_seconds 到期。无法读取的查询(例如无效的 HogQL)会立即导致步骤失败,而临时错误会在超时前重试。

jobs: my_job: steps: - uses: eas/posthog_wait_for_metric with: query: SELECT count() FROM events WHERE event = '$exception' AND timestamp > now() - INTERVAL 15 MINUTE operator: lt threshold: 10
属性
属性类型必填描述
querystringHogQL 查询。第一行的第一列必须是单个数字。
operatorstring比较运算符。可以是 lt、lte、gt、gte 或 eq 之一。当 value <operator> threshold 成立时,步骤将清除。
thresholdnumber用于与查询结果进行比较的值。
timeout_secondsnumber等待的最长时间,以秒为单位。默认为 600。
interval_secondsnumber检查之间的时间间隔,以秒为单位。默认为 30。
api_keystringPostHog 个人 API 密钥。默认为 POSTHOG_CLI_API_KEY 环境变量。需要 query:read 权限范围。
project_idstringPostHog 项目 ID。默认为 POSTHOG_CLI_PROJECT_ID 环境变量。
输出
属性类型描述
valuestring满足比较条件的指标值。
eas/posthog_wait_for_metric 源代码

在 GitHub 上查看 eas/posthog_wait_for_metric 函数的源代码。

eas/posthog_wait_for_query

暂停工作流,直到 HogQL 查询返回 true。当条件更容易直接在查询中表达时,可以使用此函数。如果是带有明确阈值的数值比较,请改用 eas/posthog_wait_for_metric。

当第一行第一列的值为 true 或非零数字时,该步骤会完成,因此请编写查询以选择单个布尔值,例如 SELECT count() > 100 FROM events。

jobs: my_job: steps: - uses: eas/posthog_wait_for_query with: query: SELECT count() > 0 FROM events WHERE event = 'smoke_test_passed' AND timestamp > now() - INTERVAL 30 MINUTE
属性
属性类型必填描述
querystringHogQL 查询。当第一行的第一列为 true 或非零数字时,该步骤将清除。
timeout_secondsnumber最大等待时间,以秒为单位。默认为 600。
interval_secondsnumber检查之间的间隔时间,以秒为单位。默认为 30。
api_keystringPostHog 个人 API 密钥。默认为 POSTHOG_CLI_API_KEY 环境变量。需要 query:read 作用域。
project_idstringPostHog 项目 ID。默认为 POSTHOG_CLI_PROJECT_ID 环境变量。
eas/posthog_wait_for_query 源代码

在 GitHub 上查看 eas/posthog_wait_for_query 函数的源代码。

eas/posthog_annotation

在项目时间线上创建 PostHog 注释。注释会显示在 PostHog 图表上,因此可以方便地在相关指标旁标记构建、发布和其他里程碑。

jobs: my_job: steps: - uses: eas/posthog_annotation with: content: Published update to production
属性
属性类型必填描述
contentstring注释文本。
date_markerstring注释固定到的 ISO 8601 时间戳。默认为当前时间。
api_keystringPostHog 个人 API 密钥。默认为 POSTHOG_CLI_API_KEY 环境变量。需要 annotation:write 作用域。
project_idstringPostHog 项目 ID。默认为 POSTHOG_CLI_PROJECT_ID 环境变量。
ignore_errorboolean当值为 true 时,会记录网络错误或意外响应,但不会使步骤失败。默认为 false。权限错误始终会使步骤失败。
eas/posthog_annotation 源代码

在 GitHub 上查看 eas/posthog_annotation 函数的源代码。

eas/posthog_upload_sourcemaps

将 JavaScript 源映射上传到 PostHog,以便 PostHog 在错误跟踪中对堆栈跟踪进行符号化处理。请在生成 bundle 的步骤之后、同一作业中运行此函数,以确保 bundle 和源映射在磁盘上可用。使用 npx expo export --source-maps 导出,并根据源映射指南配置 PostHog Metro 配置,使 bundle 携带能够将其与源映射匹配的分块 ID。

jobs: publish_update: steps: - uses: eas/checkout - uses: eas/install_node_modules - run: npx expo export --source-maps - uses: eas/posthog_upload_sourcemaps with: directory: dist
属性
属性类型必填描述
directorystring包含 bundle 和源映射的目录,相对于工作目录。默认为 dist。
api_keystringPostHog 个人 API 密钥。默认为 POSTHOG_CLI_API_KEY 环境变量。需要源映射上传权限。
project_idstringPostHog 项目 ID。默认为 POSTHOG_CLI_PROJECT_ID 环境变量。
ignore_errorboolean当为 true 时,上传失败会被记录,但不会导致步骤失败。默认为 false。
eas/posthog_upload_sourcemaps 源代码

在 GitHub 上查看 eas/posthog_upload_sourcemaps 函数的源代码。

自定义函数

在项目中定义可复用的步骤序列,并通过 uses 使用相对路径调用它们。路径必须是静态的字面字符串,不能包含 ${{ }} 插值或反斜杠。自定义函数调用接受与内置函数调用相同的字段:id、name、with、if 和 env。不要在调用步骤上设置 working_directory,而应在函数的内部步骤上设置。将每个自定义函数存储在包含 function.yml 或 function.yaml 文件的目录中。自定义函数中的步骤使用与自定义作业步骤相同的格式。有关组织文件、嵌套函数以及从作业或钩子调用函数的详细信息,请参阅 EAS Workflows 中的自定义函数。

你的 function.yml 文件支持以下顶层属性:name、description、inputs、outputs 和 runs。EAS Workflows 会拒绝未知的顶层属性。

函数 name

自定义函数的可选显示名称,会显示在作业日志中。

name: Greet

函数 description

对自定义函数功能的可选描述。

description: Prints a greeting for the given name.

函数 inputs

调用者可以通过 with: 传递给自定义函数的输入值。你可以通过两种方式声明输入。

简写形式是名称列表。每个输入都会成为一个没有默认值的可选字符串输入:

inputs: - who

完整形式是包含以下属性的对象列表:

属性类型必填描述
namestring输入的名称。使用 ${{ inputs.<name> }} 访问该输入。
typestring输入类型:string、boolean、number 或 json。默认为 string。
default_valuevaries未提供输入时 EAS Workflows 使用的值。必须与 type 匹配。
allowed_valuesarray可以为此输入传递的值。
requiredboolean是否必须提供此输入。默认为 false。
inputs: - name: who type: string default_value: world - name: platform type: string allowed_values: [android, ios] required: true

在自定义函数的步骤中,使用 ${{ inputs.<name> }} 读取输入。

函数 outputs

声明自定义函数向调用者公开的输出值,格式为以输出名称为键的映射:

属性必填描述
value解析为输出值的表达式,例如 ${{ steps.<id>.outputs.<name> }}。
description输出的描述。
outputs: message: value: '${{ steps.make.outputs.message }}' description: The rendered greeting.

EAS Workflows 会将每个输出公开为字符串。使用 ${{ steps.<call_id>.outputs.<name> }} 读取输出。使用调用步骤中的 id。调用者无法引用函数内部步骤的标识符。

函数 runs.steps

runs.steps 是必需的,并且必须至少包含一个步骤。步骤使用与自定义作业步骤相同的格式,包括 id、run、uses、if 和 working_directory。目前,自定义函数无法调用 eas/build 或 eas/maestro_test。

runs: steps: - id: make run: set-output message "Hello, ${{ inputs.who }}!"

内置 shell 函数

EAS Workflows 提供了以下 shell 函数,你可以在工作流步骤中使用它们来设置变量输出。

set-output

设置一个输出变量,其他步骤或工作流中的其他任务可以访问它。

set-output <name> <value>

用于与另一个步骤共享变量的示例:

jobs: my_job: steps: - id: step_1 run: set-output variable_1 "变量 1" - id: step_2 run: echo ${{ steps.step_1.outputs.variable_1 }} # 输出:变量 1

用于与另一个任务共享变量的示例:

jobs: job_1: outputs: variable_1: ${{ steps.step_1.outputs.variable_1 }} steps: - id: step_1 run: set-output variable_1 "变量 1" job_2: needs: [job_1] steps: - run: echo ${{ needs.job_1.outputs.variable_1 }} # 输出:变量 1

set-env

设置一个环境变量,该变量可供同一任务中的后续步骤使用。在一个步骤的命令中使用 export 导出的环境变量不会自动暴露给其他步骤。若要与其他步骤共享环境变量,请使用 set-env 可执行文件。

set-env <name> <value>

set-env 需要传入两个参数:环境变量的名称和值。例如,set-env NPM_TOKEN "abcdef" 会将 $NPM_TOKEN 变量及其值 abcdef 暴露给后续步骤。

用于与另一个步骤共享环境变量的示例:

jobs: my_job: steps: - name: 设置环境变量 run: | # 仅使用 export 只会让它在当前步骤中可用 export LOCAL_VAR="仅在此步骤中" # 使用 set-env 会让它在后续步骤中可用 set-env SHARED_VAR "在后续步骤中可用" # SHARED_VAR 目前在当前步骤的环境中还不可用 echo "LOCAL_VAR: $LOCAL_VAR" # 输出:仅在此步骤中 echo "SHARED_VAR: $SHARED_VAR" # 输出:(空) - name: 使用共享变量 run: | # SHARED_VAR 现在可用了 # @info # echo "SHARED_VAR: $SHARED_VAR" # 输出:在后续步骤中可用 # @end #

在任务之间共享环境变量

set-env 函数只会在同一任务内与其他步骤共享环境变量。若要在不同任务之间共享值,请使用任务的 outputs 配合 set-output,并通过接收任务上的 env 属性传递它们:

jobs: job_1: outputs: my_value: ${{ steps.step_1.outputs.my_value }} steps: - id: step_1 run: set-output my_value "来自 job_1 的值" job_2: needs: [job_1] env: MY_VALUE: ${{ needs.job_1.outputs.my_value }} steps: - run: echo "MY_VALUE: $MY_VALUE" # 输出:来自 job_1 的值