build: consolidate fastlane
9
fastlane/Appfile
Normal file
@@ -0,0 +1,9 @@
|
||||
# Android
|
||||
json_key_file(ENV["GOOGLE_PLAY_KEY_FILE"])
|
||||
package_name("dev.casraf.pantry")
|
||||
|
||||
# iOS
|
||||
app_identifier("dev.casraf.pantry")
|
||||
apple_id(ENV["APPLE_ID"])
|
||||
itc_team_id(ENV["ITC_TEAM_ID"])
|
||||
team_id(ENV["APPLE_TEAM_ID"])
|
||||
3
fastlane/Deliverfile
Normal file
@@ -0,0 +1,3 @@
|
||||
# The Deliverfile allows you to store various App Store Connect metadata
|
||||
# For more information, check out the docs
|
||||
# https://docs.fastlane.tools/actions/deliver/
|
||||
188
fastlane/Fastfile
Normal file
@@ -0,0 +1,188 @@
|
||||
require "digest"
|
||||
require "json"
|
||||
|
||||
# -- Shared helpers --
|
||||
|
||||
def version_info
|
||||
pubspec = File.read(File.expand_path("../pubspec.yaml", __dir__))
|
||||
version = pubspec.match(/^version:\s*(.+)$/)[1].strip
|
||||
name, build = version.split("+")
|
||||
{ name: name, build: build }
|
||||
end
|
||||
|
||||
def version_name
|
||||
v = version_info
|
||||
"#{v[:build]} (#{v[:name]})"
|
||||
end
|
||||
|
||||
def changelog_notes
|
||||
version = version_info[:name]
|
||||
changelog_path = File.expand_path("../CHANGELOG.md", __dir__)
|
||||
return "Release #{version}" unless File.exist?(changelog_path)
|
||||
|
||||
changelog = File.read(changelog_path)
|
||||
escaped = Regexp.escape(version)
|
||||
pattern = /^## (?:\[#{escaped}\]|#{escaped}[\s(]).*?\n(.*?)(?=^## |\z)/m
|
||||
match = changelog.match(pattern)
|
||||
return "Release #{version}" unless match
|
||||
|
||||
match[1].strip
|
||||
.gsub(/\s*\(\[[\da-f]+\]\([^)]+\)\)/, "")
|
||||
.gsub(/^\*\s+\*\*[^*]+:\*\*\s*/m, "- ")
|
||||
.gsub(/^\*\s+/, "- ")
|
||||
.gsub(/^### /, "")
|
||||
.gsub(/\n{3,}/, "\n\n")
|
||||
.strip
|
||||
.then { |n| n.empty? ? "Release #{version}" : n }
|
||||
end
|
||||
|
||||
# -- Android --
|
||||
|
||||
default_platform(:android)
|
||||
|
||||
platform :android do
|
||||
# Google Play enforces a 500-char limit on release notes per language.
|
||||
PLAY_NOTES_MAX = 500
|
||||
PLAY_NOTES_TRAILER = "\n\n… see full notes on GitHub."
|
||||
|
||||
def play_changelog
|
||||
notes = changelog_notes
|
||||
return notes if notes.length <= PLAY_NOTES_MAX
|
||||
|
||||
budget = PLAY_NOTES_MAX - PLAY_NOTES_TRAILER.length
|
||||
truncated = notes[0, budget]
|
||||
last_newline = truncated.rindex("\n")
|
||||
truncated = truncated[0, last_newline] if last_newline && last_newline > budget / 2
|
||||
truncated.rstrip + PLAY_NOTES_TRAILER
|
||||
end
|
||||
|
||||
# -- Image change detection --
|
||||
|
||||
IMAGE_HASH_CACHE = File.expand_path(".image_hashes.json", __dir__)
|
||||
|
||||
def current_image_hashes
|
||||
root = File.expand_path("metadata/android", __dir__)
|
||||
return {} unless Dir.exist?(root)
|
||||
|
||||
files = Dir.glob(File.join(root, "**/images/**/*")).select { |f| File.file?(f) }
|
||||
files.sort.each_with_object({}) do |path, acc|
|
||||
rel = path.sub("#{root}/", "")
|
||||
acc[rel] = Digest::SHA256.file(path).hexdigest
|
||||
end
|
||||
end
|
||||
|
||||
def cached_image_hashes
|
||||
return {} unless File.exist?(IMAGE_HASH_CACHE)
|
||||
JSON.parse(File.read(IMAGE_HASH_CACHE))
|
||||
rescue StandardError
|
||||
{}
|
||||
end
|
||||
|
||||
def images_changed?
|
||||
current_image_hashes != cached_image_hashes
|
||||
end
|
||||
|
||||
def save_image_hashes
|
||||
File.write(IMAGE_HASH_CACHE, JSON.pretty_generate(current_image_hashes))
|
||||
end
|
||||
|
||||
desc "Upload AAB to Google Play"
|
||||
lane :deploy do |options|
|
||||
version_code = version_info[:build]
|
||||
changelog_dir = File.expand_path("metadata/android/en-US/changelogs", __dir__)
|
||||
FileUtils.mkdir_p(changelog_dir)
|
||||
File.write(File.join(changelog_dir, "#{version_code}.txt"), play_changelog)
|
||||
|
||||
changed = images_changed?
|
||||
UI.message(changed ? "Images changed — uploading." : "Images unchanged — skipping.")
|
||||
|
||||
upload_to_play_store(
|
||||
aab: File.expand_path("../build/app/outputs/bundle/release/app-release.aab", __dir__),
|
||||
track: options[:track] || "internal",
|
||||
release_status: options[:status] || "draft",
|
||||
version_name: version_name,
|
||||
metadata_path: File.expand_path("metadata/android", __dir__),
|
||||
skip_upload_images: !changed,
|
||||
skip_upload_screenshots: !changed,
|
||||
)
|
||||
|
||||
save_image_hashes if changed
|
||||
end
|
||||
|
||||
desc "Sync metadata and screenshots only (no AAB upload)"
|
||||
lane :metadata do
|
||||
changed = images_changed?
|
||||
UI.message(changed ? "Images changed — uploading." : "Images unchanged — skipping.")
|
||||
|
||||
upload_to_play_store(
|
||||
skip_upload_aab: true,
|
||||
skip_upload_apk: true,
|
||||
metadata_path: File.expand_path("metadata/android", __dir__),
|
||||
skip_upload_images: !changed,
|
||||
skip_upload_screenshots: !changed,
|
||||
)
|
||||
|
||||
save_image_hashes if changed
|
||||
end
|
||||
|
||||
desc "Promote a release from one track to another"
|
||||
lane :promote do |options|
|
||||
from = options[:from] || "internal"
|
||||
to = options[:to] || "production"
|
||||
status = options[:status] || "draft"
|
||||
|
||||
upload_to_play_store(
|
||||
track: from,
|
||||
track_promote_to: to,
|
||||
release_status: status,
|
||||
version_name: version_name,
|
||||
skip_upload_aab: true,
|
||||
skip_upload_apk: true,
|
||||
skip_upload_metadata: true,
|
||||
skip_upload_changelogs: true,
|
||||
skip_upload_images: true,
|
||||
skip_upload_screenshots: true,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# -- iOS --
|
||||
|
||||
platform :ios do
|
||||
def api_key
|
||||
key_id = ENV.fetch("APP_STORE_API_KEY")
|
||||
app_store_connect_api_key(
|
||||
key_id: key_id,
|
||||
issuer_id: ENV.fetch("APP_STORE_ISSUER_ID"),
|
||||
key_filepath: File.join(ENV.fetch("APP_STORE_KEY_PATH"), "AuthKey_#{key_id}.p8"),
|
||||
)
|
||||
end
|
||||
|
||||
def find_ipa
|
||||
ipa_path = Dir[File.expand_path("../build/ios/ipa/*.ipa", __dir__)].first
|
||||
UI.user_error!("No IPA found in build/ios/ipa/. Run 'make ios-build' first.") unless ipa_path
|
||||
ipa_path
|
||||
end
|
||||
|
||||
desc "Upload to TestFlight"
|
||||
lane :beta do
|
||||
upload_to_testflight(
|
||||
api_key: api_key,
|
||||
ipa: find_ipa,
|
||||
changelog: changelog_notes,
|
||||
skip_waiting_for_build_processing: true,
|
||||
)
|
||||
end
|
||||
|
||||
desc "Upload to App Store"
|
||||
lane :release do
|
||||
deliver(
|
||||
api_key: api_key,
|
||||
ipa: find_ipa,
|
||||
skip_metadata: true,
|
||||
skip_screenshots: true,
|
||||
submit_for_review: false,
|
||||
release_notes: { "en-US" => changelog_notes },
|
||||
)
|
||||
end
|
||||
end
|
||||
48
fastlane/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
fastlane documentation
|
||||
----
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
## Android
|
||||
|
||||
### android deploy
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android deploy
|
||||
```
|
||||
|
||||
Upload AAB to Google Play
|
||||
|
||||
### android metadata
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android metadata
|
||||
```
|
||||
|
||||
Sync metadata and screenshots only (no AAB upload)
|
||||
|
||||
### android promote
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android promote
|
||||
```
|
||||
|
||||
Promote a release from one track to another
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
1
fastlane/metadata/android/en-US/changelogs/2.txt
Normal file
@@ -0,0 +1 @@
|
||||
Release 0.1.0
|
||||
8
fastlane/metadata/android/en-US/changelogs/3.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Features
|
||||
|
||||
- add sorting by category for checklist
|
||||
- notifications support
|
||||
|
||||
Bug Fixes
|
||||
|
||||
- add bottom padding to accomodate fab
|
||||
3
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Bug Fixes
|
||||
|
||||
- sorting prefs persistence & error wrapping
|
||||
25
fastlane/metadata/android/en-US/full_description.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
Pantry is a companion app for the Nextcloud Pantry server app. It lets you and your household members collaborate on shared checklists, a photo board, and a notes wall — all stored on your own Nextcloud server.
|
||||
|
||||
* Checklists
|
||||
Create shopping lists and to-do lists with categories, quantities, recurring items, and images. Drag to reorder, sort by name or date, and check items off as you go.
|
||||
|
||||
* Photo Board
|
||||
Upload and organize photos into folders. Add captions, drag to reorder, and browse everything in a clean grid view.
|
||||
|
||||
* Notes Wall
|
||||
Keep shared notes with your household. Color-code them, write in markdown, and pin the important stuff where everyone can see it.
|
||||
|
||||
* Your data, your server
|
||||
Pantry connects directly to your self-hosted Nextcloud instance. No accounts to create, no cloud services in between. Your data never leaves your server.
|
||||
|
||||
* Features
|
||||
- Shared checklists with categories, quantities, and recurrence
|
||||
- Photo board with folders, captions, and multi-upload
|
||||
- Color-coded notes wall
|
||||
- Drag-and-drop reordering everywhere
|
||||
- Multi-select for bulk actions
|
||||
- Offline caching for fast loading
|
||||
- Material Design 3 with dark mode support
|
||||
- Nextcloud Login Flow v2 authentication
|
||||
|
||||
* Pantry requires a Nextcloud server with the Pantry app installed. Visit the project page for setup instructions.
|
||||
BIN
fastlane/metadata/android/en-US/images/featureGraphic.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 517 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 400 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 455 KiB |
|
After Width: | Height: | Size: 99 KiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Manage your household with your Nextcloud — lists, photos & notes.
|
||||
1
fastlane/metadata/android/en-US/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
Nextcloud Pantry
|
||||