Skip to content
Merged

canary #6410

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/skills/finalize-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ sync 側の走行は **必須**。master→dev 差分が 0 件の場合のみ自

sync が **スキップ**(差分 0 件)された場合はこの手順を飛ばす。新規作成・流用いずれかで dev<-master PR が存在する場合のみ実行する。**緩和→マージ→復元は 1 つの bash 呼び出しにまとめ、`set +e` でマージ失敗を握って復元を無条件実行する**(途中で関数が分かれて復元が飛ぶ事故を防ぐ)。

**マージ前にコンフリクトを確認する。** `gh pr view <n> --json mergeable,mergeStateStatus` が `CONFLICTING` を返す場合、`master` から特定コミットだけを cherry-pick したリリース(`create-release-pr` の「この変更だけ」指定など)の後に起きる **版数ファイルのねじれ** が典型。このときは Ruleset 緩和より先に `sync-dev-from-master` の「版数ファイルのコンフリクト解決」に従って版数を解決し(本番版数の判断はユーザー承認を取る)、PR を `MERGEABLE` にしてから 6-3 以降へ進む。`mergeable` はプッシュ直後に非同期で古い値を返すことがあるため、`git merge-base --is-ancestor origin/dev origin/chore/dev-from-master` で構造的な包含も確認するとよい。

1. マージ対象 PR 番号を確定(手順 5 で新規作成 or 流用した PR)。ローカルが `chore/dev-from-master` に居るとブランチ削除で支障が出るため `git switch dev`(または安全な枝)へ退避する。
2. `OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)` を解決。プレフライトの「マージ方式制約」記録を使う:
- dev が `merge` を許可済み → **緩和不要**。そのまま手順 6-5 のマージへ。
Expand Down
51 changes: 51 additions & 0 deletions .claude/skills/sync-dev-from-master/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ description: Open a dev<-master merge PR that syncs master back into dev after a

- 何もコミットは積まない(master 先端そのまま)。biome 等のフォーマッタは走らせない(新規コミット無し)。
- push 前に、対象 SHA(`git rev-parse origin/master`)・取り込まれるコミット件数・本文に入れる version をユーザーに提示して承認を取る。
- **例外**: この PR が版数ファイルで衝突する場合(`master` から特定 PR だけ cherry-pick したリリースの後に起きる。後述の「版数ファイルのコンフリクト解決」を参照)は、この枝に `origin/dev` をマージして解決コミットを 1 つだけ積む。それ以外は master 先端そのまま。

5. **PR 本文を組み立て(テンプレ厳守・全節を実内容で埋める)**

Expand Down Expand Up @@ -160,6 +161,56 @@ description: Open a dev<-master merge PR that syncs master back into dev after a
- テスト欄のチェック状態(全 OFF + 説明文あり)
- 使用した `release_version`(どこから取ったか)

## 版数ファイルのコンフリクト解決(cherry-pick / hotfix リリース後)

通常の「dev から丸ごと」リリースでは `master` が `dev` の完全な祖先になるため、この同期 PR は衝突しない(手順 4 のとおり master 先端そのままで済む)。しかし **リリースブランチを `master` から切って特定 PR だけ cherry-pick したリリース**(`create-release-pr` に「この変更だけ」と指定したホットフィックス型など)では、`dev` を `master` に取り込んでいないため、`master` のリリース版数と `dev` の canary bump 版数が **ねじれたまま** 残り、この同期 PR が版数ファイルで衝突する。

衝突するのは版数ファイルのみで、アプリコードは衝突しない:

- `android/app/build.gradle`(`versionCode` / `versionName`)
- `app.config.ts`(`version` / `buildNumber` / `versionCode`)
- `ios/TrainLCD.xcodeproj/project.pbxproj`(`MARKETING_VERSION` / `CURRENT_PROJECT_VERSION`)

### 解決方針: semver はリリース版、ビルド番号は最大値

| 種別 | 採用する側 | 理由 |
| ---- | ---- | ---- |
| semver(`version` / `versionName` / `MARKETING_VERSION`) | `master`(リリース版数) | `dev` をリリース済みバージョンへ前進させる。過去 PR #6396 も semver 競合をリリース版で解決している |
| ビルド番号(`versionCode` / `CURRENT_PROJECT_VERSION` / `buildNumber`) | `max(dev, master)`(通常は `dev` 側が大きい) | ストアはビルド番号の単調増加を要求する。canary で既発行の番号より下げると次回 bump で衝突する |

### 解決手順

1. `chore/dev-from-master`(= master 先端)に居る状態で `origin/dev` をマージする(手順 4 の「コミットを積まない」原則の唯一の例外):

```bash
git switch chore/dev-from-master
git merge --no-ff --no-commit origin/dev
```

2. 衝突した版数 3 ファイルを master 側(`--ours`)で確定してから、ビルド番号だけ `dev` 側の最大値へ引き上げる(下は master=530/2743・dev=531/2744 の例):

```bash
git checkout --ours android/app/build.gradle app.config.ts ios/TrainLCD.xcodeproj/project.pbxproj
sed -i 's/versionCode 100000530/versionCode 100000531/g' android/app/build.gradle
sed -i "s/buildNumber: '2743'/buildNumber: '2744'/g; s/versionCode: 100000530/versionCode: 100000531/g" app.config.ts
sed -i 's/CURRENT_PROJECT_VERSION = 2743;/CURRENT_PROJECT_VERSION = 2744;/g' ios/TrainLCD.xcodeproj/project.pbxproj
```

これらの版数ファイルは master↔dev で数値以外の差分が無い(`git diff origin/dev origin/master -- <path>` で確認できる)ため、`--ours` で master を採ってもコンテンツは失われない。

3. **`dev` への正味の変化が semver だけ**(ビルド番号は据え置き)であることを確認してからマージコミットを作成し push する:

```bash
git add android/app/build.gradle app.config.ts ios/TrainLCD.xcodeproj/project.pbxproj
git diff origin/dev HEAD # semver(例 10.9.0 -> 10.9.1)のみが出るのが正
git commit -m "origin/dev をマージし版数競合を解決(semver=<release>、ビルド番号=<max>)"
git push origin chore/dev-from-master
```

4. 以降は通常どおり merge commit でマージする(`finalize-release` が Ruleset 一時緩和つきで実行する)。マージ後は dev HEAD が 2 親の merge commit になり、`git rev-list --count origin/dev..origin/master` が `0`(dev が master を完全包含)になることを検証する。

**semver をリリース版数へ更新する判断とビルド番号の採用値は本番の版数に関わるため、自動で確定せずユーザーに確認する。**

## 注意事項

- **Squash merge 禁止**。これがこのスキルの存在理由の半分。実行時と完了報告で二重に明示する。
Expand Down
8 changes: 4 additions & 4 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.dev"
versionNameSuffix "-dev"
versionCode 100000531
versionName "10.9.0"
versionCode 100000532
versionName "10.9.1"
}
prod {
dimension "environment"
versionCode 100000531
versionName "10.9.0"
versionCode 100000532
versionName "10.9.1"
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const IS_DEV = process.env.APP_VARIANT === 'dev';
export default {
name: 'TrainLCD',
slug: 'trainlcd',
version: '10.9.0',
version: '10.9.1',
plugins: [
'expo-image',
'expo-font',
Expand Down Expand Up @@ -52,15 +52,15 @@ export default {
},
},
ios: {
buildNumber: '2744',
buildNumber: '2745',
scheme: IS_DEV ? 'CanaryTrainLCD' : 'ProdTrainLCD',
bundleIdentifier: IS_DEV ? 'me.tinykitten.trainlcd.dev' : 'me.tinykitten.trainlcd',
supportsTablet: true,
},
android: {
package: IS_DEV ? 'me.tinykitten.trainlcd.dev' : 'me.tinykitten.trainlcd',
permissions: [],
versionCode: 100000531,
versionCode: 100000532,
},
owner: 'trainlcd',
experiments: {
Expand Down
1 change: 1 addition & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@
"telemetryDescription": "Your device's geographic coordinates are sent to our analytics server. The information is used only for analytics.",
"etaAssistTitle": "Improve arrival detection",
"etaAssistDescription": "When enabled, in sections where GPS accuracy drops such as subways, the app uses the server's estimated arrival times (ETA) to assist arrival detection. GPS remains the source of truth for arrival and current location; ETA is only an aid.",
"batterySettings": "Battery",
"powerSavingLocationTitle": "Power-saving location mode",
"powerSavingLocationDescription": "When enabled, location accuracy is lowered to a battery-friendly level and iOS pauses tracking automatically while you are stopped, further reducing battery drain and heat on long rides. The lower accuracy may delay or shift station detection and arrival announcements. The relaxed update frequency is already part of the default settings. It also turns on automatically while your device is in low-power mode.",
"passStationLabel": "Pass"
Expand Down
1 change: 1 addition & 0 deletions assets/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@
"telemetryDescription": "お使いの端末の地理的座標を解析用サーバに送信します。送信された情報は解析以外に使用されません。",
"etaAssistTitle": "到着判定の改善",
"etaAssistDescription": "有効にすると、地下鉄などGPSの精度が落ちる区間で、サーバーの到着予測(ETA)を使って到着判定を補助します。到着や現在地はGPSが基準で、ETAはあくまで補助です。",
"batterySettings": "バッテリー",
"powerSavingLocationTitle": "省電力測位モード",
"powerSavingLocationDescription": "有効にすると、測位精度を電池優先まで下げ、停車中はiOSが測位を自動休止して、長時間の乗車での電池消費と発熱をさらに減らします。精度の低下により駅の判定や到着案内が遅れたりずれたりする場合があります。位置情報の更新頻度の緩和は標準設定に組み込まれています。端末の省電力モード中は自動的に有効になります。",
"passStationLabel": "通過"
Expand Down
44 changes: 22 additions & 22 deletions ios/TrainLCD.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2407,7 +2407,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
Expand Down Expand Up @@ -2446,7 +2446,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TrainLCD;
Expand Down Expand Up @@ -2505,7 +2505,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down Expand Up @@ -2561,7 +2561,7 @@
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MARKETING_VERSION = 10.9.0;
MARKETING_VERSION = 10.9.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
Expand Down Expand Up @@ -2611,7 +2611,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down Expand Up @@ -2663,7 +2663,7 @@
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MARKETING_VERSION = 10.9.0;
MARKETING_VERSION = 10.9.1;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
Expand All @@ -2690,7 +2690,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
Expand Down Expand Up @@ -2729,7 +2729,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
Expand Down Expand Up @@ -2940,7 +2940,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/CanaryRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -2991,7 +2991,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3042,7 +3042,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/ProdWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3100,7 +3100,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3151,7 +3151,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/CanaryWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3208,7 +3208,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3256,7 +3256,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/ProdRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3307,7 +3307,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3526,7 +3526,7 @@
CODE_SIGN_ENTITLEMENTS = ProdAppClip/ProdAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down Expand Up @@ -3582,7 +3582,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down Expand Up @@ -3632,7 +3632,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryAppClip/CanaryAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand All @@ -3656,7 +3656,7 @@
"@executable_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 10.9.0;
MARKETING_VERSION = 10.9.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
Expand Down Expand Up @@ -3690,7 +3690,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2744;
CURRENT_PROJECT_VERSION = 2745;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand All @@ -3710,7 +3710,7 @@
"@executable_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 10.9.0;
MARKETING_VERSION = 10.9.1;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PODS_ROOT = "${SRCROOT}/Pods";
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"web": "expo start --web",
"lint": "biome check ./src",
"format": "biome format ./src --write",
"test": "TZ=UTC jest",
"test": "cross-env TZ=UTC jest",
"typecheck": "tsc --noEmit",
"watch:test": "TZ=UTC jest --watch",
"watch:test": "cross-env TZ=UTC jest --watch",
"gql:codegen": "graphql-codegen --config utils/codegen.ts",
"version:bump": "node scripts/bump-version.js",
"postinstall": "patch-package"
Expand Down Expand Up @@ -167,5 +167,5 @@
}
},
"name": "trainlcd",
"version": "10.9.0"
"version": "10.9.1"
}
2 changes: 1 addition & 1 deletion src/components/Permitted.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
);
// NOTE: powerSavingLocationEnabledAtom はここでは復元しない。effect復元だと
// 継続測位がデフォルト精度で一度起動してから再起動されるため、
// atom定義側(store/atoms/experimental.ts)でMMKVから同期的に初期値を確定している。
// atom定義側(store/atoms/battery.ts)でMMKVから同期的に初期値を確定している。

if (themePreferenceKey) {
setThemePreference(themePreferenceKey as ThemePreference);
Expand Down
Loading
Loading