From 6384035f888ab5f88fcfea2c78376bbef22bd28b Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 30 Mar 2026 14:37:31 +0100 Subject: [PATCH 1/7] Fork sync: upstream-main branch tracking upstream's main --- .../simcapture-sync-fork-upstream-main.yml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/simcapture-sync-fork-upstream-main.yml diff --git a/.github/workflows/simcapture-sync-fork-upstream-main.yml b/.github/workflows/simcapture-sync-fork-upstream-main.yml new file mode 100644 index 00000000000..7cf534a4ad2 --- /dev/null +++ b/.github/workflows/simcapture-sync-fork-upstream-main.yml @@ -0,0 +1,64 @@ +name: Sync upstream repo's main into this fork repo's upstream-main + +on: + schedule: + - cron: '0 0 * * 1-5' + workflow_dispatch: + +concurrency: + group: simcapture-sync-fork-upstream-main + cancel-in-progress: false + +jobs: + simcapture-sync-fork-upstream-main: + runs-on: ubuntu-latest + permissions: + contents: write + env: + CURRENT_FORK_REPOSITORY: ${{ github.repository }} + SOURCE_UPSTREAM_REPOSITORY: dhis2/dhis2-android-capture-app + SOURCE_BRANCH: main + DESTINATION_BRANCH: upstream-main + steps: + - name: Set this repo's upstream-main branch to match the upstream repo's main branch + env: + GH_TOKEN: ${{ secrets.GH_WORKFLOW_SYNC_PAT_SIMCAPTURE }} + run: | + set -euo pipefail + + source_head_sha=$( + gh api "repos/$SOURCE_UPSTREAM_REPOSITORY/branches/$SOURCE_BRANCH" --jq '.commit.sha' + ) + destination_head_sha=$( + gh api "repos/$CURRENT_FORK_REPOSITORY/branches/$DESTINATION_BRANCH" --jq '.commit.sha' + ) + + echo "Source $SOURCE_UPSTREAM_REPOSITORY:$SOURCE_BRANCH branch head before sync: $source_head_sha." + echo "Destination $CURRENT_FORK_REPOSITORY:$DESTINATION_BRANCH branch head before sync: $destination_head_sha." + + if [[ "$destination_head_sha" == "$source_head_sha" ]]; then + echo "Destination branch already matches source." + exit 0 + fi + + gh api --method PATCH "repos/$CURRENT_FORK_REPOSITORY/git/refs/heads/$DESTINATION_BRANCH" \ + --raw-field sha="$source_head_sha" \ + --field force=true >/dev/null + echo "Force-updated destination $DESTINATION_BRANCH branch head to $source_head_sha." + + post_sync_source_head_sha=$( + gh api "repos/$SOURCE_UPSTREAM_REPOSITORY/branches/$SOURCE_BRANCH" --jq '.commit.sha' + ) + post_sync_destination_head_sha=$( + gh api "repos/$CURRENT_FORK_REPOSITORY/branches/$DESTINATION_BRANCH" --jq '.commit.sha' + ) + + echo "Source $SOURCE_UPSTREAM_REPOSITORY:$SOURCE_BRANCH branch head after sync: $post_sync_source_head_sha." + echo "Destination $CURRENT_FORK_REPOSITORY:$DESTINATION_BRANCH branch head after sync: $post_sync_destination_head_sha." + + if [[ "$post_sync_destination_head_sha" != "$post_sync_source_head_sha" ]]; then + echo "Error: Branch heads $SOURCE_UPSTREAM_REPOSITORY:$SOURCE_BRANCH and $CURRENT_FORK_REPOSITORY:$DESTINATION_BRANCH do not match after sync." >&2 + exit 1 + fi + + echo "Branch sync complete." From 9871e196f06a51190dfd9773e69dd5e8c1c0f08a Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 30 Mar 2026 18:35:24 +0100 Subject: [PATCH 2/7] Fork sync: PRs on upstream releases --- .../simcapture-upstream-release-pr.yml | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 .github/workflows/simcapture-upstream-release-pr.yml diff --git a/.github/workflows/simcapture-upstream-release-pr.yml b/.github/workflows/simcapture-upstream-release-pr.yml new file mode 100644 index 00000000000..19e8de26305 --- /dev/null +++ b/.github/workflows/simcapture-upstream-release-pr.yml @@ -0,0 +1,203 @@ +name: Create PRs for upstream releases merged into upstream-main + +on: + workflow_run: + workflows: + - "Sync upstream repo's main into this fork repo's upstream-main" + types: + - completed + workflow_dispatch: + pull_request: + types: + - closed + +concurrency: + group: simcapture-upstream-release-pr + cancel-in-progress: false + +jobs: + simcapture-upstream-release-pr: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + env: + CURRENT_FORK_OWNER: ${{ github.repository_owner }} + CURRENT_FORK_REPOSITORY: ${{ github.repository }} + CURRENT_FORK_MAIN_BRANCH: main + UPSTREAM_REPOSITORY: dhis2/dhis2-android-capture-app + UPSTREAM_TRACKING_MAIN_BRANCH: upstream-main + steps: + - name: Create or update PR branches for new upstream releases + env: + GH_TOKEN: ${{ secrets.GH_WORKFLOW_SYNC_PAT_SIMCAPTURE }} + run: | + set -euo pipefail + + is_commit_reachable_from_ref() { + commit_sha="$1" + ref_name="$2" + + if ! compare_json=$(gh api "repos/$CURRENT_FORK_REPOSITORY/compare/$commit_sha...$ref_name"); then + return 1 + fi + + merge_base_sha=$(jq -r '.merge_base_commit.sha // empty' <<< "$compare_json") + [[ "$merge_base_sha" == "$commit_sha" ]] + } + + create_or_update_branch_ref() { + branch_name="$1" + target_sha="$2" + encoded_branch_name=$(jq -rn --arg value "$branch_name" '$value | @uri') + + if gh api "repos/$CURRENT_FORK_REPOSITORY/git/ref/heads/$encoded_branch_name"; then + gh api --method PATCH "repos/$CURRENT_FORK_REPOSITORY/git/refs/heads/$encoded_branch_name" \ + --raw-field sha="$target_sha" \ + --field force=true + echo "Updated $branch_name branch to $target_sha." + else + gh api --method POST "repos/$CURRENT_FORK_REPOSITORY/git/refs" \ + --raw-field ref="refs/heads/$branch_name" \ + --raw-field sha="$target_sha" + echo "Created $branch_name branch at $target_sha." + fi + } + + main_head_sha=$(gh api "repos/$CURRENT_FORK_REPOSITORY/branches/$CURRENT_FORK_MAIN_BRANCH" --jq '.commit.sha') + main_tree_sha=$(gh api "repos/$CURRENT_FORK_REPOSITORY/git/commits/$main_head_sha" --jq '.tree.sha') + + declare -A release_sha_by_branch=() + declare -a ordered_release_branches=() + release_prs_file=$(mktemp) + trap 'rm -f "$release_prs_file"' EXIT + + gh api --method GET --paginate search/issues \ + -f q="repo:$UPSTREAM_REPOSITORY is:pr is:merged base:main head:release/" \ + -f per_page=100 \ + --jq '.items[].number' \ + | while IFS= read -r pr_number; do + [[ -z "$pr_number" ]] && continue + gh api "repos/$UPSTREAM_REPOSITORY/pulls/$pr_number" \ + --jq '{number: .number, merged_at: .merged_at, merge_commit_sha: .merge_commit_sha, head_ref: .head.ref, title: .title}' + printf '\n' + done > "$release_prs_file" + + if [[ ! -s "$release_prs_file" ]]; then + echo "No upstream release PRs merged into upstream main branch found." + exit 0 + fi + + while IFS= read -r pr_json; do + [[ -z "$pr_json" ]] && continue + + pr_number=$(jq -r '.number' <<< "$pr_json") + release_branch=$(jq -r '.head_ref' <<< "$pr_json") + release_sha=$(jq -r '.merge_commit_sha' <<< "$pr_json") + + echo "Inspecting upstream PR #$pr_number for $release_branch at $release_sha." + + if ! is_commit_reachable_from_ref "$release_sha" "$UPSTREAM_TRACKING_MAIN_BRANCH"; then + echo "Skipping upstream PR #$pr_number because $release_sha is not reachable from $UPSTREAM_TRACKING_MAIN_BRANCH." + continue + fi + + if is_commit_reachable_from_ref "$release_sha" "$CURRENT_FORK_MAIN_BRANCH"; then + echo "Latest upstream release merge already reachable from $CURRENT_FORK_MAIN_BRANCH: $release_sha ($release_branch via upstream PR #$pr_number)." + break + fi + + if [[ -n ${release_sha_by_branch[$release_branch]+x} ]]; then + continue + fi + + release_sha_by_branch["$release_branch"]="$release_sha" + ordered_release_branches+=("$release_branch") + done < <( + jq -sc '. | sort_by(.merged_at) | reverse | .[] | select(.merged_at != null and .merge_commit_sha != null and (.head_ref | startswith("release/")))' "$release_prs_file" + ) + + if [[ ${#ordered_release_branches[@]} -eq 0 ]]; then + echo "No newer upstream release merges require PRs." + exit 0 + fi + + for ((id=${#ordered_release_branches[@]} - 1; id >= 0; id--)); do + release_branch="${ordered_release_branches[$id]}" + release_version="${release_branch#release/}" + pr_branch="upstream-release/$release_version" + release_sha="${release_sha_by_branch[$release_branch]}" + release_tree_sha=$(gh api "repos/$CURRENT_FORK_REPOSITORY/git/commits/$release_sha" --jq '.tree.sha') + + echo "Processing $release_branch at $release_sha." + + if [[ "$release_tree_sha" == "$main_tree_sha" ]]; then + echo "Skipping $pr_branch because its tree already matches $CURRENT_FORK_MAIN_BRANCH." + continue + fi + + existing_prs=$( + gh api --method GET "repos/$CURRENT_FORK_REPOSITORY/pulls" \ + -f state=all \ + -f base="$CURRENT_FORK_MAIN_BRANCH" \ + -f head="$CURRENT_FORK_OWNER:$pr_branch" + ) + + open_pr_number=$(jq -r '.[] | select(.state == "open") | .number' <<< "$existing_prs" | head -n 1) + matching_pr_number=$(jq -r --arg sha "$release_sha" '.[] | select(.head.sha == $sha) | .number' <<< "$existing_prs" | head -n 1) + + if [[ -n "$open_pr_number" && "$open_pr_number" != "null" ]]; then + create_or_update_branch_ref "$pr_branch" "$release_sha" + echo "Updated existing PR branch $pr_branch for open PR #$open_pr_number." + continue + fi + + if [[ -n "$matching_pr_number" && "$matching_pr_number" != "null" ]]; then + echo "Skipping duplicate PR creation for $pr_branch at $release_sha because PR #$matching_pr_number already exists." + continue + fi + + create_or_update_branch_ref "$pr_branch" "$release_sha" + + pr_title="[Automatic] Upstream release $release_version" + pr_body=$(cat < Date: Tue, 31 Mar 2026 00:25:25 +0100 Subject: [PATCH 3/7] Fork release signing --- .../simcapture-github-release-signed-apk.yml | 130 ++++++++++++++++++ app/build.gradle.kts | 2 +- 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/simcapture-github-release-signed-apk.yml diff --git a/.github/workflows/simcapture-github-release-signed-apk.yml b/.github/workflows/simcapture-github-release-signed-apk.yml new file mode 100644 index 00000000000..2fda9ea3943 --- /dev/null +++ b/.github/workflows/simcapture-github-release-signed-apk.yml @@ -0,0 +1,130 @@ +name: Build signed SimCapture APK release + +on: + workflow_dispatch: + push: + branches: + - main + +concurrency: + group: simcapture-github-release-signed-apk + cancel-in-progress: false + +env: + MAIN_PROJECT_MODULE: app + +jobs: + simcapture-github-release-signed-apk: + runs-on: ubuntu-latest + permissions: + contents: write + env: + CURRENT_FORK_REPOSITORY: ${{ github.repository }} + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Get current date and time + id: date-time + run: echo "dateTimeUtc=$(date -u +'%Y-%m-%d-%H%M')" >> "$GITHUB_OUTPUT" + + - name: Set up JDK + uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: '17' + cache: gradle + + - name: Change wrapper permissions + run: chmod +x ./gradlew + + - name: Read upstream app version + id: read-version + working-directory: ./gradle + run: echo "vName=$(grep '^vName' libs.versions.toml | awk -F' = ' '{print $2}' | tr -d '\"')" >> "$GITHUB_OUTPUT" + + - name: Determine next SimCapture fork release + id: release-info + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + last_fork_number=0 + + while IFS= read -r tag_name; do + [[ "$tag_name" =~ ^SimCapture-DHIS2-v[0-9]+(\.[0-9]+)*-fork-([0-9]+)$ ]] || continue + + candidate_fork_number="${BASH_REMATCH[2]}" + if (( candidate_fork_number > last_fork_number )); then + last_fork_number="$candidate_fork_number" + fi + done < <( + gh api --paginate "repos/$CURRENT_FORK_REPOSITORY/releases?per_page=100" --jq '.[].tag_name' + ) + + next_fork_number=$((last_fork_number + 1)) + release_tag="SimCapture-DHIS2-v${{ steps.read-version.outputs.vName }}-fork-${next_fork_number}" + release_apk_name="${release_tag}-signed-release.apk" + release_apk_path="$RUNNER_TEMP/$release_apk_name" + + { + echo "forkNumber=$next_fork_number" + echo "releaseTag=$release_tag" + echo "releaseApkName=$release_apk_name" + echo "releaseApkPath=$release_apk_path" + } >> "$GITHUB_OUTPUT" + + - name: Decode keystore + id: decode-keystore + # Third-party action - pinned to commit SHA. + uses: timheuer/base64-to-file@604a8926a81a2da120d09b06bb76da9bba5aee6e + with: + fileName: dhis_keystore.jks + encodedString: ${{ secrets.KEYSTORE_BASE64 }} + + - name: Build signed release APK + run: ./gradlew app:assembleDhis2Release + env: + SIGNING_KEY_ALIAS: ${{ secrets.KEY_ALIAS }} + SIGNING_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} + SIGNING_STORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + SIGNING_KEYSTORE_PATH: ${{ steps.decode-keystore.outputs.filePath }} + + - name: Rename signed release APK for SimCapture release + run: | + set -euo pipefail + + cp \ + "${MAIN_PROJECT_MODULE}/build/outputs/apk/dhis2/release/dhis2-v${{ steps.read-version.outputs.vName }}.apk" \ + "${{ steps.release-info.outputs.releaseApkPath }}" + + - name: Upload signed release APK artifact + uses: actions/upload-artifact@v7.0.0 + with: + name: ${{ steps.release-info.outputs.releaseTag }} + path: ${{ steps.release-info.outputs.releaseApkPath }} + + - name: Create GitHub release with signed APK + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + release_notes=$(cat < Date: Tue, 31 Mar 2026 07:29:29 +0100 Subject: [PATCH 4/7] SimCapture-specific README section --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 1bc9fccc045..1320171d5fb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ +# SimCapture + +DHIS2 data and tracker capture app for Android to support integration with SimprintsID. + +Summary of changes comparing to upstream [dhis2/dhis2-android-capture-app](https://github.com/dhis2/dhis2-android-capture-app): + +| Feature | File / line of code | Type of change | Description | +|-----------------------------------------|--------------------------------------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------| +| Infra: fork sync from upstream | [simcapture-sync-fork-upstream-main.yml](.github/workflows/simcapture-sync-fork-upstream-main.yml) | New file | GitHub Action to sync upstream's `main` to this repo's `upstream-main` nightly on Mon-Fri | +| Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | +| Infra: signed APK releases | [simcapture-github-release-signed-apk.yml](.github/workflows/simcapture-github-release-signed-apk.yml) | New file | GitHub Action to create a GitHub Release on a merge to `main` | +| Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts) | Code change | App's Package ID set to `com.simprints.simcapture` | +| Docs: fork-specific README | [README.md#L1-L20](README.md) | Code change | This section in README | + +SimCapture [releases](https://github.com/Simprints/SimCapture/releases) have the following naming scheme: `SimCapture-DHIS2--fork-`. +An example of a release APK name: `SimCapture-DHIS2-v3.3.1-fork-1-signed-release.apk`. + +The upstream `README` is preserved below. + + # README # [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=dhis2_dhis2-android-capture-app&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=dhis2_dhis2-android-capture-app) From f8d8f682aab6eb1e39bf0d8c9b41e65223852c9b Mon Sep 17 00:00:00 2001 From: Alex / Oleksii Date: Tue, 31 Mar 2026 10:51:32 +0100 Subject: [PATCH 5/7] README fix: line references Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1320171d5fb..eb1568259f9 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ Summary of changes comparing to upstream [dhis2/dhis2-android-capture-app](https | Infra: fork sync from upstream | [simcapture-sync-fork-upstream-main.yml](.github/workflows/simcapture-sync-fork-upstream-main.yml) | New file | GitHub Action to sync upstream's `main` to this repo's `upstream-main` nightly on Mon-Fri | | Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | | Infra: signed APK releases | [simcapture-github-release-signed-apk.yml](.github/workflows/simcapture-github-release-signed-apk.yml) | New file | GitHub Action to create a GitHub Release on a merge to `main` | -| Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts) | Code change | App's Package ID set to `com.simprints.simcapture` | -| Docs: fork-specific README | [README.md#L1-L20](README.md) | Code change | This section in README | +| Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts#L85) | Code change | App's Package ID set to `com.simprints.simcapture` | +| Docs: fork-specific README | [README.md#L1-L20](README.md#L1-L20) | Code change | This section in README | SimCapture [releases](https://github.com/Simprints/SimCapture/releases) have the following naming scheme: `SimCapture-DHIS2--fork-`. An example of a release APK name: `SimCapture-DHIS2-v3.3.1-fork-1-signed-release.apk`. From ad50efc67d96373340fea7dc48e0a8d80867c84e Mon Sep 17 00:00:00 2001 From: Alex / Oleksii Date: Tue, 31 Mar 2026 10:52:59 +0100 Subject: [PATCH 6/7] README.md clenaup Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb1568259f9..ca493c619b6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Summary of changes comparing to upstream [dhis2/dhis2-android-capture-app](https | Feature | File / line of code | Type of change | Description | |-----------------------------------------|--------------------------------------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------| | Infra: fork sync from upstream | [simcapture-sync-fork-upstream-main.yml](.github/workflows/simcapture-sync-fork-upstream-main.yml) | New file | GitHub Action to sync upstream's `main` to this repo's `upstream-main` nightly on Mon-Fri | -| Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | +| Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | | Infra: signed APK releases | [simcapture-github-release-signed-apk.yml](.github/workflows/simcapture-github-release-signed-apk.yml) | New file | GitHub Action to create a GitHub Release on a merge to `main` | | Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts#L85) | Code change | App's Package ID set to `com.simprints.simcapture` | | Docs: fork-specific README | [README.md#L1-L20](README.md#L1-L20) | Code change | This section in README | From dbed5352b3d927a2e3bd091a8e7d02e6c28f8ebd Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2026 12:45:09 +0100 Subject: [PATCH 7/7] SimCapture-specific GitHub Actions filtering --- .../simcapture-disable-upstream-workflows.yml | 33 +++++++++++++++++++ README.md | 23 +++++++++---- 2 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/simcapture-disable-upstream-workflows.yml diff --git a/.github/workflows/simcapture-disable-upstream-workflows.yml b/.github/workflows/simcapture-disable-upstream-workflows.yml new file mode 100644 index 00000000000..c6d2517e356 --- /dev/null +++ b/.github/workflows/simcapture-disable-upstream-workflows.yml @@ -0,0 +1,33 @@ +name: Disable non-SimCapture and non-Copilot workflows + +on: + push: + branches: [main] + paths: ['.github/workflows/**'] + workflow_dispatch: + +jobs: + disable-non-prefixed-workflows: + runs-on: ubuntu-latest + steps: + - name: Disable workflows without approved prefixes + env: + GH_TOKEN: ${{ secrets.GH_WORKFLOW_SYNC_PAT_SIMCAPTURE }} + run: | + set -euo pipefail + + gh api "repos/${{ github.repository }}/actions/workflows" \ + --paginate --jq '.workflows[] | select(.state == "active") | [.id, .path] | @tsv' \ + | while IFS=$'\t' read -r wf_id wf_path; do + filename=$(basename "$wf_path") + + case "$filename" in + simcapture-*|copilot-*) + echo "Kept enabled: $filename" + ;; + *) + gh api --method PUT "repos/${{ github.repository }}/actions/workflows/$wf_id/disable" + echo "Disabled: $filename" + ;; + esac + done diff --git a/README.md b/README.md index ca493c619b6..7e4e65a6c00 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,28 @@ DHIS2 data and tracker capture app for Android to support integration with SimprintsID. +### Changes + Summary of changes comparing to upstream [dhis2/dhis2-android-capture-app](https://github.com/dhis2/dhis2-android-capture-app): -| Feature | File / line of code | Type of change | Description | -|-----------------------------------------|--------------------------------------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------| -| Infra: fork sync from upstream | [simcapture-sync-fork-upstream-main.yml](.github/workflows/simcapture-sync-fork-upstream-main.yml) | New file | GitHub Action to sync upstream's `main` to this repo's `upstream-main` nightly on Mon-Fri | -| Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | -| Infra: signed APK releases | [simcapture-github-release-signed-apk.yml](.github/workflows/simcapture-github-release-signed-apk.yml) | New file | GitHub Action to create a GitHub Release on a merge to `main` | -| Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts#L85) | Code change | App's Package ID set to `com.simprints.simcapture` | -| Docs: fork-specific README | [README.md#L1-L20](README.md#L1-L20) | Code change | This section in README | +| Feature | File / line of code | Type of change | Description | +|-----------------------------------------|----------------------------------------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------| +| Infra: fork sync from upstream | [simcapture-sync-fork-upstream-main.yml](.github/workflows/simcapture-sync-fork-upstream-main.yml) | New file | GitHub Action to sync upstream's `main` to this repo's `upstream-main` nightly on Mon-Fri | +| Infra: automatic PR on upstream release | [simcapture-upstream-release-pr.yml](.github/workflows/simcapture-upstream-release-pr.yml) | New file | GitHub Action to open a PR when `upstream-main` has an upstream release newly merged into it | +| Infra: signed APK releases | [simcapture-github-release-signed-apk.yml](.github/workflows/simcapture-github-release-signed-apk.yml) | New file | GitHub Action to create a GitHub Release on a merge to `main` | +| Infra: signed APK releases | [app/build.gradle.kts#L85](app/build.gradle.kts#L85) | Code change | App's Package ID set to `com.simprints.simcapture` | +| Infra: GitHub Actions filtering | [simcapture-disable-upstream-workflows.yml](.github/workflows/simcapture-disable-upstream-workflows.yml) | New file | GitHub Action to limit allowed Actions to the ones starting with `simcapture-` or `copilot-` | +| Docs: fork-specific README | [README.md#L1-L29](README.md#L1-L29) | Code change | This section in README | + +### Releases SimCapture [releases](https://github.com/Simprints/SimCapture/releases) have the following naming scheme: `SimCapture-DHIS2--fork-`. An example of a release APK name: `SimCapture-DHIS2-v3.3.1-fork-1-signed-release.apk`. +### GitHub Actions + +The workflows of this fork repo should start with `simcapture-`. + The upstream `README` is preserved below.