distribute_cli 2.8.0
distribute_cli: ^2.8.0 copied to clipboard
Quick way to distribute your app to playstore and appstore
2.8.0 #
Added #
-
Independent tasks can run in parallel.
-j 2,-j auto, orparallel: trueindistribution.yaml. Given the usualandroid.build → android.publish ios.build → ios.publishthe two chains overlap, so
android.publishuploads whileios.buildis still compiling. Jobs inside a task stay strictly ordered — that ordering is the point, since a publish must not start before the build it uploads.flutter buildis serialised even when tasks overlap: two builds in the same checkout share.dart_tool/andbuild/, and--pubhas both runningpub getover the same directory, which Flutter does not lock. Everything around the compile still runs concurrently, which is where the time goes — so two build-only tasks gain nothing, and build-and-publish pipelines gain the whole upload.Each task's output is collected and printed as one block when it finishes, rather than interleaved live. The indentation counter and the output sink are now per-task rather than global, which is what makes that possible.
--fail-faststops starting new tasks; ones already running finish, because a build cannot be safely killed part way through. -
Globally coordinated start gaps for parallel tasks. Use
parallel: {tasks: 3, gap: 15s}or--gap 15sto avoid starting every task or store upload at once. Durations acceptms,s,m, andh.parallel: true,parallel: false,parallel: auto, and numeric values remain backwards compatible. -
Persistent run state and safe resume. Every real run records job status, attempts, resolved version, and artifact metadata in
.distribute/last-run.json.--resumeand--retry-failedskip successful work,--statusinspects the saved state,--state-filechanges its location, and--force-resumeexplicitly overrides compatibility checks. A build is skipped only when every saved artifact still has the same size and SHA-256. The configuration, selected operation, and committed Git revision are part of the resume fingerprint, and Ctrl-C flushes state before stopping work. -
Run, task, and job lifecycle hooks.
preandpostaccept a command or a structured step with arguments, environment, working directory, timeout,continue-on-error, andon: always|success|failure. Hooks share the normal variable expansion and secret redaction, receiveDISTRIBUTE_*context in their environment, and post-hooks can use${{ARTIFACT}}and${{ARTIFACT_DIR}}. Dry runs print hooks without executing them. -
Job reliability controls.
retry-delayspaces retry attempts andtimeoutbounds each job attempt. Timeouts cancel in-process HTTP requests, send SIGTERM to tracked child processes, and escalate to SIGKILL when a child does not exit.on-error: stop|continueprovides the same policy in YAML that--fail-fastprovides on the command line. -
Run-level automatic versioning. A
version:section resolves one shared version before parallel work begins, injects${{VERSION_NAME}}and${{VERSION_CODE}}, and includes it in state and JSON reports. Build numbers can come frompubspec.yaml, an increment, the Git commit count, a timestamp, or a positive literal. Optionalwrite-backchanges only the top-levelversion:line and is disabled during dry runs. -
Safe automatic and standalone cleanup. A
clean:section can run after success, failure, or every run, after all post-hooks have finished.distribute clean --flutter|--outputs|--all [--dry-run]exposes the same operation directly. Cleanup only accepts paths inside the project and refuses symlinks or directories containing metadata, credentials, logs, or run state. -
Huawei AppGallery publishing.
publisher.huaweianddistribute publish huaweiupload APK/AAB artifacts, resolve the AppGallery app ID, attach the uploaded package, poll compilation, update localized release notes, and optionally submit the release. Authentication supports the recommended Service Account PS256 JWT flow and the legacy API client flow. The create wizard and configuration validator understand the new publisher. -
Wildcard artifact paths. Any
file-pathaccepts*,?,[abc]and**:distribution/android/output/*.aab,build/**/*.ipa. A publisher that uploads one binary takes the newest match whose extension agrees withbinary-type, soout/*beside both an APK and its mapping file still uploads the APK. The GitHub publisher attaches every match, which is howout/*.apkuploads each split-per-ABI build as its own asset. A pattern matching nothing is an error during a real run and a note during--dry-run.
Changed #
- The minimum Dart SDK is now 3.2.0.
- GitHub and Huawei REST work participate in job cancellation, so an expired timeout or Ctrl-C does not leave uploads running in the background.
- Parallel stop-on-error releases workers waiting on a task-start gap immediately. Tasks that had already started are still allowed to finish.
- Explicit operation keys must be exactly
taskortask.job; malformed keys such astask.job.extraare rejected instead of silently ignoring segments.
Fixed #
- Concurrent jobs no longer race while replacing the same run-state temporary file. State writes are serialised and atomically replace the destination on platforms with different rename semantics; malformed state files now produce a controlled format error.
- Resuming a task no longer skips a downstream saved success after an upstream build had to run again. Once one ordered job is invalidated, the remainder of that task runs again as well.
- Long task gaps, retry delays, and Huawei compilation polling now wake immediately after the matching stop, timeout, or interrupt signal.
- One failing in-process cancellation callback no longer prevents other HTTP operations and child processes from being terminated.
- Flutter build output streams are fully drained before artifacts are moved, so late diagnostics are not lost.
- Duration validation rejects negative, zero-when-forbidden, and non-finite values consistently. Job and hook timeout values also round-trip through YAML using the keys the parser accepts.
- Git-derived version codes fail with an actionable message in shallow clones instead of silently producing a non-monotonic build number. Literal build numbers must be greater than zero.
- Cleanup now runs
flutter cleanfrom the project root, tracks the process for interruption, protects custom credential/state/log paths, handles case-insensitive filesystems, and rejects targets reached through a symlinked parent. - Huawei upload requests include
releaseType, normalize Huawei's legacyfileDestUlrspelling tofileDestUrl, reject incomplete upload responses, and wait for package compilation before submitting. - Unexpected lifecycle hook, variable, report, notification, and state errors are converted to a controlled non-zero run result instead of escaping as an unhandled exception.
Security #
- Huawei bearer tokens and API client IDs are removed from the HTTP client while sending a file to the presigned upload host, then restored for AppGallery API calls. Credentials are never forwarded to an unrelated upload origin.
- Cleanup refuses to remove an output directory that contains configured Fastlane or Huawei credentials, custom logs, protected metadata, or the active resume state, including through symlink and case-insensitive path tricks.
2.7.1 #
Added #
-
distribute changelog— release notes from the git history.The range defaults to everything since the previous tag, which is what one release actually contains. The boundary is the nearest tagged ancestor of the range's end, not the newest tag by date: a tag cut on a side branch or added retroactively would otherwise make a release re-list commits that had already shipped while dropping ones that had not.
Conventional commit prefixes are used for grouping when they are there and ignored when they are not, so a repository with ordinary commit messages gets a flat list rather than an error.
--format plaindrops the headings for stores that show plain text,-owrites to a file, and--aihands the result to the configured model for an editorial pass under an instruction that forbids inventing or dropping a change.It warns when the range is empty, and when it is run in a shallow clone — the default for most CI checkouts — where the notes would silently be missing everything before the cut.
-
${{CHANGELOG}},${{CHANGELOG_PLAIN}}and${{CHANGELOG_RANGE}}— the same notes as variables, so a publisher can fillrelease-notesorrelease-bodywithout a wrapper script. The history is read once per run and shared by every job that references it. Outside a git repository the placeholder is left unresolved andvalidatereports it, rather than quietly publishing empty notes. -
A
changelog:section indistribution.yamlsetting the range, the format, grouping, hashes, merges and the optional AI pass.ai: trueis off by default because it sends your commit subjects to the model on every publish; when it is on and the request fails, the job fails rather than shipping raw commit subjects nobody asked for. -
A spinner while a build or upload runs. Those stages produce nothing on screen below
--verboseand can last minutes, so the CLI looked hung. One line, rewritten in place, carrying the step and its elapsed time.It is drawn only on a real terminal and never under
--quiet,--silentor--verbose, so piped output, CI logs and the log file are untouched. Any log line printed while it runs erases it first, so the two never share a row, and the line is truncated to the pane width — a wrapped spinner cannot be erased, because a carriage return only returns to the start of the last row.
2.7.0 #
Everything from 2.4.0 onwards is one upgrade for anyone coming from 2.3.5. The behaviour changes worth knowing about before you update:
distribute run --jsonis a flag rather than an option (use--json-filefor a path);permission: autois no longer honoured fromdistribution.yaml; a%{{command}}substitution that fails now stops the job instead of silently substituting its error text; and a publisher refuses an artifact whose build mode does not match, rather than promoting whatever it finds.
Added #
distribute ai "<request>"— ask a model to pick the right command:distribute ai "tolong build yang ios"→distribute run -o ios.build. The assistant never composes a shell string. It fills in a constrained schema whose only commands arerun,validateanddoctor, and whose operation keys come from a generated list of the keys that exist in this project — so it cannot invent a task, and cannot reach anything a typed command could not. Chosen commands run through the sameCommandRunneras a hand-typed one.- Two provider backends behind one interface.
AiProviderhas an OpenAI-compatible adapter (OpenAI, OpenRouter, Groq, Together, DeepSeek, a local Ollama — anything servingPOST /chat/completions) and an Anthropic Messages API adapter. They differ in more than a URL — bearer token vsx-api-key, nestedfunctionvsinput_schema, a JSON-string argument blob vs a parsed map, and Anthropic's refusals arriving as a successful HTTP 200 that has to be checked before reading any content. - Three permission modes, set by
permission:or-p:manual(show the command, confirm before running — the default),auto(run it straight away),plan(print it, never run). distribute ai --setup— an interactive wizard with numbered menus and non-echoing secret entry. It asks whether to store the settings machine-wide (~/.distribute/ai.json, writtenchmod 600) or in the project.ai:section indistribution.yaml, which overrides the machine-wide store. Layering, most specific first: CLI flags →distribution.yaml→ machine-wide store → environment (OPENAI_API_KEY/ANTHROPIC_API_KEY).api-keyaccepts${{VAR}}, and the wizard defaults to writing a placeholder rather than the literal key, sincedistribution.yamlis normally committed. Whatever the source, the resolved key is registered with the logger and masked everywhere.
Changed #
- The
createwizards were rebuilt. They used to dump a list of tasks and ask you to retype a key from it, reject a duplicate only after every question had been answered, and write the file without showing you what it was about to add. Now the task is picked from a numbered list that shows the jobs it already has, the key is suggested from the name and validated at the question, the detected package name is offered as a default instead of being forced, and platforms and publishers are multi-select (1,3,1-2orall). The result is shown as a review block and confirmed before anything is written; answering no leaves the file untouched. distribute createaccepts-c/--configlike every other command. It writes to the configuration file, so needing the global--configfor it was a trap.distribute createsilently deleted every comment indistribution.yaml. The document is re-encoded from scratch, so adding one task threw away every#line and all the blank-line grouping in a file that is hand-maintained and committed. It now says so: the wizard shows the warning as part of the review, before the single confirm, and the scripted form warns without blocking, since automation asked for the change explicitly.
Fixed #
- A failing
%{{command}}substituted its own error text into the build.build-name: "%{{git describe}}"outside a git repository produced--build-name=fatal: not a git repository ..., which split into extra arguments on the flutter command line — and the run reported success. A missing binary substituted an empty string just as quietly. Both now stop the job and name the command that failed. - A variable declared with no value blanked the real environment variable.
FIREBASE_TOKEN:with nothing after it overwrote the exported credential with an empty string, resolved the placeholder to nothing, and leftvalidatereporting no problems. A key with no value is now a declaration, not an assignment. - The publisher promoted whatever it found, including a debug APK. With an
empty output directory the scoring made a lone
app-debug.apkthe best candidate and uploaded it. An artifact labelled with a different build mode is now refused outright rather than ranked lower. - Copying an artifact onto itself deleted it. Pointing
output:at the directory the build already writes to made source and target the same file; the target was deleted and then copied "from", and the run only reported a failed copy. xcrun --file-pathwas declared, marked mandatory, and never read. The publisher uploaded whatever sat indistribution/ios/output, so passing an explicit path silently shipped a different, usually stale, IPA.- The debug-symbol archive could come from the wrong build variant. Matching
was by substring and ties were broken by name length, so flavor
devalso matcheddevQaRelease, and a leftoverdebugReleasebeat an exactrelease. Variants are matched exactly now, with the loose match kept as a fallback ordered by modification time. - An unset value reached publishers as the literal string
"null". The round trip through variable substitution stringified everything, so an omittedtarget-commitishwas sent to the GitHub API as a branch namednull. distribute buildprinted nothing at all when it failed. flutter's own diagnostics go to the verbose channel, and the standalone build commands return straight to the process exit code, so the console stayed empty.distribute run --dry-runfailed for any configuration with a GitHub publisher, because it insisted on an artifact the rehearsal had not built.run -o task.jobcould exit 0 having run nothing. A job present injobsbut absent from the task'sworkflowswas re-filtered out after being selected. An explicit job key now overrides the workflow ordering,--listmarks jobs a whole-task run would skip, and a run that executed nothing is a failure rather than a silent success.- A malformed
pubspec.yamltook the whole CLI down with exit 255. Project metadata is read before the error handling was installed; it is optional, so a failure there now warns and continues. - Mistyped YAML no longer surfaces as a raw Dart type error with no location.
workflows: j,key: 7,builder.android: apk, a non-textwebhook-urland the fastlaneversion-code/rollout/version-codes-to-retainkeys all produce a message naming the file and the key.continue-on-error: "true"andversion-code: "42"— the quoted forms editors produce — are understood now rather than rejected. distribute doctorreported a tool that is not installed as "found but exited with code 127".--json-file -produced no report at all.- The failure hint no longer points at a log file when
--log-file ""disabled file logging. - Colours are decided from the stream the human output actually goes to, so
--jsonpiped to a parser keeps its colours on the terminal. validatewarns when a job appears twice inworkflows, and when the inertoutput:key is set.- The
buildandpublishsub-command descriptions were three lines of prose each; they are one line now, andexample/example.mdreproduces the real help output verbatim. - The publisher wizard's tool question read stdin directly, so it was the one prompt that neither validated its answer nor stopped at end-of-input.
distribute create job -wagainst a configuration with no tasks asked every question before failing; it now says to create a task first and stops.- The README documented
distribute create task builder -w, which is not a command. - A wizard started without a terminal never stopped.
stdin.readLineSyncreturns null once input ends and keeps returning null, sodistribute create task -win CI recursed until the stack overflowed — 14,000 frames of trace instead of an error — and the newer prompts spun on the same empty answer forever. Every prompt now treats end-of-input as an abort and exits64with a message saying to pass the values as options.confirmandselectabort too rather than silently taking their default, which would have answered "yes" to questions like write the API key intodistribution.yaml? - Asking for a secret no longer fails outright where terminal echo cannot be switched off. Hiding the input is attempted first and, if the terminal refuses, the prompt warns that what is typed will be visible instead of crashing.
distribute run --jsonswallowed the next flag as its value.--jsontook a path, sodistribute run --json --silentwrote the report to a file literally named--silentand the run was never silenced.--jsonis now a flag that prints the report to stdout, and--json-file <path>writes it to disk. When the report goes to stdout the human readable log moves to stderr, sodistribute run --json > report.jsonproduces a parseable file while progress still shows on the terminal.- A mistyped configuration key was silently ignored.
binary-typ: aabparses fine and quietly builds an APK — a wrong artifact that only surfaces once it reaches a store.distribute validatenow reports unknown keys at every level with a nearest-match suggestion. They stay warnings, not errors, so a configuration written for a newer CLI still runs on an older one. - A configuration with an
arguments:key crashed. The field was typed as a map of parsed objects while being populated with raw YAML maps, so any config declaring it died with aTypeErrorbefore anything ran.validatealso points out that nothing reads the key yet. distributewith no command exited0. A script that reached this by mistake read it as success; it is a usage error and now exits64.- A missing mandatory option exited
1, indistinguishable from a failed build. Theargspackage reports it as anArgumentErrorrather than aUsageException, so it looked like a crash. It now exits64like every other usage error. - The main example in the README declared a
workflowsentry that referenced no job, so the very first configuration a reader copies failed to validate. - Pointing
--configat a directory reported it as "not found", which sends the reader looking for the wrong problem. It now says what is actually wrong. - Help text corrections:
create taskno longer describes itself as creating "a task or job", andrun --operationdocuments thetask.jobform it actually accepts. - The global
--configoption never worked. Every sub-command declares its own--configwith adistribution.yamldefault, and that default shadowed the global option on every invocation — sodistribute --config custom.yaml runsilently readdistribution.yaml. A sub-command's flag now wins only when it was actually typed. - A command chosen by the assistant is run with the configuration file the
assistant was pointed at, instead of falling back to
distribution.yaml. distribute ai --setupwarns before rewriting adistribution.yamlthat contains comments — re-encoding the document drops them — and offers the YAML to paste in by hand instead.- An invalid
provider:orpermission:in theai:section now names every place the value could have come from, rather than reporting a bareInvalid argument(s). - The Anthropic adapter no longer sends
output_config.effort. It suits the task, but older Claude models reject it outright and the model is the user's choice. - Writing the machine-wide AI store no longer fails when
chmodis unavailable.
Security #
- Two credentials reached the log file in the clear. The run header masks
credential options by name, but only matched their long spellings, so
publish xcrun -p <app-specific-password>andpublish fastlane -J '<service-account-json>'were written out verbatim. Short forms are now masked too, per sub-command —-pis a password underxcrunbut the package name undercreate job, so the letter alone is not enough to decide. A test walks the real argument parsers and fails if a credential option grows an abbreviation that is not covered. permission: autois no longer honoured fromdistribution.yaml. That file travels with the repository, so a cloned project could pre-authorise its own builds and uploads with no confirmation. The project file may still restrict tomanualorplan; grantingautonow requires-p autoor the machine-wide store. The demotion is announced, with the two ways to enable it.- The endpoint is printed, and a redirected key is flagged. A project file
setting
base-urlwhile the API key came from the machine-wide store would send that key wherever the repository pointed, and the URL was never shown. It is now part of the header, and that combination warns. - Project data is fenced in the model prompt. Task and job names and descriptions were interpolated raw, after the tool's own rules, so a task description could append a section that read as new instructions and re-target the operation the assistant chose. Values are now flattened, capped and wrapped in a delimiter the prompt tells the model to treat as data.
- Model-supplied text can no longer repaint the terminal. Escape sequences were only stripped when colours were off, so a reply could erase and rewrite the confirmation line the user was about to answer. Everything that comes back over the network is stripped and truncated before it is printed.
- A reply truncated by the token limit is refused. Both adapters accepted a
tool_useblock cut short bymax_tokensas if it were complete — a partial{"command":"run"}becomes a full-configuration run. - Overriding
--ai-providerno longer leaves the previous provider's key, model and endpoint in place, which produced a configuration nobody asked for and a 404 blaming settings the user never touched.
2.6.0 #
Changed #
- Redesigned the terminal output. The
[INFO]/[SUCCESS]prefixes and=======banners are gone, replaced by a symbol based, indented view (▸task,›job,✓/✗/!outcomes) with de-emphasised secondary text. Only what changes state is coloured, so failures actually stand out. - The terminal and the log file no longer share a format. The log file now
gets one timestamped, level prefixed line per message
(
12:13:51.140 ERROR ...) and records every level regardless of the terminal verbosity - including under--silent. - A job now prints the command it is about to run instead of dumping its whole
configuration. The full config moved behind
--verbose. - The run summary is keyed by the operation ref (
android.publish), so a failed row can be pasted straight intodistribute run -o <ref>. - Failures are reported once, by the runner, instead of by both the runner and the builder.
Fixed #
- Every flavored Android release build failed. Debug symbols were looked for
at the hardcoded
merged_native_libs/release/mergeReleaseNativeLibs/, but Gradle names that directory after the variant -prodRelease/mergeProdReleaseNativeLibs- and older AGP versions omit the task subdirectory entirely. The directory was therefore never found, and a missing directory returned a non-zero exit code, so a build that had already produced and copied its artifact was reported as failed. The layout is now discovered by searching, and symbol problems are warnings: they can no longer fail a build whose binary is already on disk.generate-debug-symbolsdefaults totrue, so this affected every flavored release. - Debug symbols ignored the job's
outputand were always written todistribution/android/output, while the fastlane publisher looks fordebug_symbols.zipnext to the binary - so a custom output silently lost them. - A stale binary from a previous build was copied into the output directory.
After a debug build followed by a release build,
app-debug.apkwas copied next toapp-release.apk; the GitHub publisher uploads every matching file in that directory, so a debug binary could ship in a release. Only the best-matching tier is copied now (a--split-per-abiset still copies in full), and artifacts left by an earlier build are pruned. - The iOS bundle identifier could resolve to the unit test target. The first
PRODUCT_BUNDLE_IDENTIFIERinproject.pbxprojwas taken verbatim, so a reordered project yielded...RunnerTests, quoted values kept their quotes, and an unresolved$(APP_ID)was returned as-is - each of which becomes a wrong--bundle-idat upload time. CompressFiles.compressignored its second parameter and always wrotedebug_symbols.zip; it also failed on Windows when the archive already existed, and threw instead of reporting a missing archiver.create job builder/create job publisherwithout--platform/--toolsreported a raw exception that never named the missing option.- The notifier only bounded its receive timeout, so an unroutable webhook host could hold the run open for the OS-level TCP timeout after all work was done.
- Streamed tool output broke the log format. A child process delivers its output as arbitrary chunks, not lines, so every line after the first in a chunk was written without a timestamp, a level or an indent. Each line is now emitted as its own record.
- ANSI escape codes from child processes leaked into
distribution.log, leaving it unreadable in an editor and awkward to grep. They are now stripped from the file (and from the terminal when colors are disabled). - A chunk ending in a newline no longer appends a blank log record.
--log-file <dir>deleted the directory and everything in it. Anything that is not a regular file is now refused.- An empty
--log-filedisables file logging, as the help text already claimed. --silentis now absolute: it can no longer be overridden per logger instance.
Added #
-q, --quiet- print failures only, flattened to one line each.--silent- print nothing; the exit code is the only signal. The log file is still written in full.- The log file opens with a run header carrying the version, the ISO timestamp, the working directory and the invocation - with credential options masked, since the header is written before any job registers its secrets.
DISTRIBUTE_ASCII=1swaps the unicode glyphs for an ASCII fallback on legacy consoles.
2.5.0 #
Fixed #
distribute publish fastlanecrashed withLateInitializationError. The standalone command dereferenced the enclosing job, which only exists when the publisher comes fromdistribution.yaml. The package name is now resolved from--package-name, then the job, then the detectedapplicationId.distribute publish firebasecrashed before doing anything, because it read an option namedcli-tokenthat the parser never declared. It now reads--token, and also honours the mandatory--file-pathit used to ignore.xcrun'svalidate-appsent-vto altool, which means verbose, not validate — so the archive was never actually validated. Validation now runs as its own--validate-apppass before the upload, and aborts the upload on failure.fastlane/firebasetool probes never drained stderr. A tool writing more than the OS pipe buffer (fastlane actionsdoes) would block forever. Both streams are now drained on every spawned process.xcrun'supload-packageoption was accepted but silently ignored.distribute createcrashed on a config without avariables:section, and on an empty YAML file.distribute initno longer callsexit()from inside a helper, so the exit code and the log file stay consistent.
Added #
- Built-in variables —
${{GIT_SHA}},${{GIT_SHORT_SHA}},${{GIT_BRANCH}},${{GIT_TAG}},${{GIT_COMMIT_COUNT}},${{GIT_COMMIT_MESSAGE}},${{GIT_AUTHOR}},${{PUBSPEC_VERSION}},${{PUBSPEC_VERSION_NAME}},${{PUBSPEC_BUILD_NUMBER}},${{PUBSPEC_NAME}},${{ANDROID_APPLICATION_ID}},${{IOS_BUNDLE_ID}},${{BUILD_DATE}},${{BUILD_TIMESTAMP}},${{HOST_OS}}. Auto-versioning no longer needs a wrapper script:build-number: "${{GIT_COMMIT_COUNT}}". Resolved lazily, and overridable. distribute doctor— probes every external tool, the configuration and the credentials, and prints what the built-in variables expand to.- Run notifications — a top level
notifications:section posts the run summary to Slack, Discord, Telegram or a generic webhook, withon: always|success|failure. Modelled at run level soon: failureactually fires. Delivery problems never change the exit code. - Artifact report — every built binary is listed with its size and SHA-256 in the run summary.
distribute run --json— machine readable run report on stdout, or--json-file <path>to write it to disk.distribute run --no-notifyto suppress notifications for one invocation.
2.4.0 #
Fixed #
distribute runnow exits with a non-zero code when a job fails. Previously every run exited0, so CI pipelines silently reported broken builds as green.dart-definesproduced an invalid--dart-definesflag. Flutter only accepts a repeated--dart-define=KEY=VALUE, so any configuration using dart defines failed with exit code 64. Values are now expanded into one flag per pair.- GitHub release assets were uploaded as
multipart/form-data. The GitHub API expects the raw bytes, so every uploaded APK/AAB/IPA was corrupted. Assets are now streamed as the raw request body with a correct content type. - A publish job no longer runs after its build job failed, which used to upload a stale artifact from a previous build.
- Credentials (Apple password, GitHub token, Firebase CI token, Google service
account JSON data) are no longer written to
distribution.logor the terminal. --obfuscatenow auto-supplies the--split-debug-infodirectory that Flutter requires, instead of failing the build with a usage error.- GitHub releases are matched by name and tag, and are no longer created as drafts by default. The previous "fall back to the latest release" behaviour could attach a build to an unrelated release and has been removed.
- A missing
variables:section no longer crashes with atype 'Null' is not a subtype of type 'Map'error; the section is optional. - Fastlane no longer appends
debug_symbols.zipto the caller'smapping-pathslist on repeated reads. - Debug symbols are copied into the output directory even when it does not exist yet.
- Errors are written to stderr, and colors are disabled automatically when the
output is piped or
NO_COLORis set.
Added #
distribute validate- parses the configuration, reports unresolved${{VAR}}placeholders and missing credential files. Use--strictto fail on warnings.distribute run --dry-run- prints every resolved command without executing it.distribute run --list- lists the available task and job keys.distribute run --fail-fast- stops at the first failing task.- Per-job
continue-on-error: trueandretry: <n>indistribution.yaml. - A run summary with per-job status, duration and attempt count.
- Global
--version,--log-fileand--no-colorflags. obfuscateandsplit-debug-infoare now supported for iOS builds too.- GitHub publisher:
binary-type,draft,prereleaseandtarget-commitish. distribute initappends the generated artifacts to.gitignore.- Test suite covering config validation, argument building, variables and logging.
Changed #
- The package no longer depends on the Flutter SDK. It never used a Flutter
API, and the dependency made the documented
dart pub global activate distribute_clifail. Installing is now a plain Dart install. - Configuration errors name the offending key and its position, for example
tasks[0].jobs[1] ('Publish') in 'distribution.yaml' is invalid: .... - Duplicate task/job keys and workflow entries that reference a missing job are rejected at parse time rather than mid-run.
- When several artifacts match, the most recently modified one is published.
- Removed the unusable
Job.fromJsonfactory, which always threw because it never constructed a builder or publisher.
2.3.5 #
- Fix dart-define-from-file
- Upgrade packages
- Flavor app supports
2.3.4 #
- Fix typo
- Read applicationId from gradleKts
2.3.3 #
- Distribute debug symbols and path separator fixes
2.3.2 #
- Windows powershall validate fastlane fixes
2.3.1 #
- Enhance documentations
2.3.0+1 #
- Windows powershell support
- Enhance logger to provide more detailed information
- Enhance code and functionality for better performance
2.2.0 #
- Add
wizardcommand to create a newdistribution.yamlfile interactively - Enhance logger to provide more detailed information
- Enhance code and functionality for better performance
2.1.2 #
- Add command substitution for
distribution.yamlvariables%{{COMMAND}} - Optimize the code
2.1.1 #
- Fix
distribute run -onot working on specific jobs - Fix wrong output for ios built
2.1.0 #
- Add output on build and publish
- Output on job's arguments
- Once build finished or publish started, binary will be copyed to the output provided
- Add
Builder.generate-debug-symbolsandPublisher.fastlane.upload-debug-symbolsfor Android - Change
distribution.yamlpatterns - Add
workflowsonTaskto sort the jobs - Add Github as a publisher
- Change publisher subcommand to directly use the publisher name
- Add
createcommand to create a new task or job on distirbution.yaml - Update documentation
- Update examples
2.0.1 #
- Add
exportOptionsPlistandexportMethodto iOS build - Solving pub.dev scores
2.0.0 #
- Refactor the code
- Refactor how to use the package
- Distribute.yaml is now used to configure the package
- Added support for
${{KEY}}to reference environment variables or custom variables fromdistribution.yaml - Updated
README.md:- Added detailed explanation for using
${{KEY}}indistribution.yaml - Enhanced examples for
distribution.yamlwith variables and tasks - Improved documentation for commands (
init,build,publish,run) - Added a section for variable substitution in
distribution.yaml - Clarified usage of environment variables and custom variables
- Added detailed explanation for using
1.0.4+4 #
- Fix Android and iOS build error logs
1.0.4+3 #
- Update code docs
1.0.4+2 #
- Update changelogs
- Update readme.md
1.0.4+1 #
- Enhance distribution.log and terminal logs
- Run firebase and fastlane same time for quick process
- Publish git logs on fastlane
- Update readme.md and add example.md
1.0.3+1 #
- Create distribution.log to record the logs
- Start distribute once task finished
1.0.2+1 #
- Builder and Publisher will be more tolerant for tools that doesn't exists
- Firebase changelogs included
- Optimize code and error appearance
1.0.1+1 #
- Add
fastlane_trackandfastlane_promote_track_to - Solve
distribute build -p - More environment on init
1.0.0+2 #
- Add documentation on the code
- Solve pub.dev scores
1.0.0+1 #
- Add distribute executable
- Fix args not working on subCommands
- Enhance command to be more clearer
1.0.0 #
- First release, look readme.md for details