From 55b65b874dccac87677a784e8314cb62cb5d92d7 Mon Sep 17 00:00:00 2001 From: "Developer @ Loverde Company" Date: Fri, 11 Sep 2026 14:07:46 -0300 Subject: [PATCH] feat: automatic date-based build number (YYYY.MM.DD.0.0.) User wants build numbers to always follow this format, incrementing across multiple builds on the same calendar day and resetting to 1 on a new day - not a manually-edited fixed string, and not the CI run counter (which just uploaded a build as '51', unrelated to the real versioning scheme). Added next_build_version, which persists {date, build_number} to a fixed path under this CI user's home directory on the Mac mini runner (~/ci-build-version-state/pedifoods.json) - state has to live outside the per-run checkout, since every CI run gets a fresh, throwaway clone under .cache/act//. assemble now passes this as the CURRENT_PROJECT_VERSION xcarg instead of the project's committed value, so every build gets a fresh, correctly-formatted, ever-increasing version automatically. --- fastlane/Fastfile | 49 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a76df60..aa363d4 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,8 +1,32 @@ # This file contains the fastlane.tools configuration for the PediFoods iOS app. # You can find the documentation at https://docs.fastlane.tools +require "date" +require "json" +require "fileutils" + default_platform(:ios) +# Build number scheme: "YYYY.MM.DD.0.0." - increments across +# builds made on the same calendar day, resets to 1 on a new day. +# Needs somewhere to remember "the last used, and for which day", +# and the per-run checkout under .cache/act// can't be +# that place - each CI run gets a fresh, throwaway clone, so anything +# written there is gone by the next run. State lives instead at a fixed +# path under this CI user's home directory on the Mac mini runner, +# which is the same machine/user across every run. +def next_build_version + state_path = File.expand_path("~/ci-build-version-state/pedifoods.json") + FileUtils.mkdir_p(File.dirname(state_path)) + + today = Date.today.strftime("%Y.%m.%d") + state = File.exist?(state_path) ? JSON.parse(File.read(state_path)) : {} + build_number = (state["date"] == today) ? state["build_number"].to_i + 1 : 1 + + File.write(state_path, JSON.generate({ "date" => today, "build_number" => build_number })) + "#{today}.0.0.#{build_number}" +end + lane :tests do run_tests( scheme: "PediFoods", @@ -17,19 +41,18 @@ lane :assemble do |options| # baked directly into PediFoods.xcodeproj's own project settings - not # overridden here. # - # CURRENT_PROJECT_VERSION is likewise never overridden here - it's - # whatever is committed in the project (manually bumped, e.g. - # "2026.09.11.0.0.1"). A prior version of this lane overrode it with - # the CI job's own run number (BUILD_NUMBER = github.run_number-style - # counter) to guarantee a unique, ever-increasing build number per - # run - but that silently replaced the real, meaningful version with - # an unrelated small integer (a build uploaded as "51" instead of the - # intended "2026.09.11.0.0.1"). Trusting the committed value means - # re-running CI against the same commit without bumping - # CURRENT_PROJECT_VERSION first will make TestFlight/App Store reject - # the upload as a duplicate build number - a clear, safe failure, - # which is the correct behavior for a manually-versioned project. - xcargs = "-skipPackagePluginValidation -skipMacroValidation" + # CURRENT_PROJECT_VERSION IS overridden here, with next_build_version + # (see top of file) rather than the project's own committed value. + # Earlier versions of this lane either used the committed value as-is + # (fine until you forget to bump it and Apple rejects a duplicate + # build number) or overrode it with the CI job's raw run-number + # counter (BUILD_NUMBER = github.run_number-style, which silently + # uploaded a build as "51" with no relation to the real version at + # all). next_build_version keeps the real date-based scheme and + # bumps only the last component automatically, so every push + # is guaranteed a fresh, correctly-formatted, ever-increasing build + # number with no manual edit needed before each run. + xcargs = "-skipPackagePluginValidation -skipMacroValidation CURRENT_PROJECT_VERSION=#{next_build_version}" build_app( scheme: "PediFoods",