From 067f3be57d8f0151d7a119188506908a53288b36 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Mar 2026 23:19:38 +0100 Subject: [PATCH 1/5] ci: route publish to NuGet.org for tags and GitHub Packages for previews; change version to 1.0.0 --- .github/workflows/publish.yml | 60 +++++++++++++++++-- README.md | 24 +++++++- ...ch.FacebookApisForAndroidComponents.csproj | 2 +- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1b02c20..83aad2c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,6 +13,10 @@ permissions: jobs: pack_and_publish: runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write steps: - uses: actions/checkout@v4 with: @@ -22,18 +26,48 @@ jobs: id: version shell: bash run: | - if [[ "${{ github.ref }}" =~ ^refs/tags/v ]]; then - REF="${{ github.ref }}" + REF="${{ github.ref }}" + EVENT="${{ github.event_name }}" + CSPROJ="src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj" + BASE_VERSION=$(grep -oE '[^<]+' "$CSPROJ" | head -n 1 | sed 's///' || echo "0.1.0") + + if [[ "$REF" =~ ^refs/tags/v ]]; then VERSION="${REF#refs/tags/v}" + PUBLISH_TARGET="nuget" + + git fetch origin +refs/heads/*:refs/remotes/origin/* + TAGGED_SHA="${{ github.sha }}" + CONTAINING_BRANCHES=$(git for-each-ref --format='%(refname:short)' refs/remotes/origin --contains "$TAGGED_SHA") + + ON_MASTER="false" + ON_RELEASE="false" + while IFS= read -r branch; do + [[ "$branch" == "origin/master" ]] && ON_MASTER="true" + [[ "$branch" == origin/release/* ]] && ON_RELEASE="true" + done <<< "$CONTAINING_BRANCHES" + + if [[ "$VERSION" == *-* ]]; then + if [[ "$ON_RELEASE" != "true" ]]; then + echo "ERROR: Pre-release tag v$VERSION must point to a commit contained in origin/release/*" + exit 1 + fi + else + if [[ "$ON_MASTER" != "true" ]]; then + echo "ERROR: Stable tag v$VERSION must point to a commit contained in origin/master" + exit 1 + fi + fi else - CSPROJ="src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj" - BASE_VERSION=$(grep -oE '[^<]+' "$CSPROJ" | head -n 1 | sed 's///' || echo "0.1.0") COMMIT_SHORT=$(git rev-parse --short HEAD) RUN_NUMBER="${{ github.run_number }}" - VERSION="${BASE_VERSION}-prerelease.${RUN_NUMBER}.${COMMIT_SHORT}" + VERSION="${BASE_VERSION}-preview.${RUN_NUMBER}.${COMMIT_SHORT}" + PUBLISH_TARGET="github" fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "publish_target=${PUBLISH_TARGET}" >> "$GITHUB_OUTPUT" echo "Package version: ${VERSION}" + echo "Publish target: ${PUBLISH_TARGET}" - uses: actions/setup-dotnet@v4 with: @@ -72,7 +106,23 @@ jobs: -o artifacts/nuget \ /p:PackageVersion="${{ steps.version.outputs.version }}" + - name: Push to NuGet.org + if: steps.version.outputs.publish_target == 'nuget' + uses: NuGet/login@v1 + id: nuget_login + with: + user: ${{ secrets.NUGET_USER }} + + - name: Push to NuGet.org + if: steps.version.outputs.publish_target == 'nuget' + run: | + dotnet nuget push artifacts/nuget/*.nupkg \ + --api-key "${{ steps.nuget_login.outputs.NUGET_API_KEY }}" \ + --source "https://api.nuget.org/v3/index.json" \ + --skip-duplicate + - name: Push to GitHub Packages + if: steps.version.outputs.publish_target == 'github' env: NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/README.md b/README.md index 410bb98..d84f5c8 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,30 @@ Pack the NuGet: ## Consumption -- Install the package from GitHub Packages (pre-release). +- Install the package from NuGet.org for public release tags. +- Install the package from GitHub Packages for internal preview builds. - Follow `Docs/Integration.md` for required AndroidManifest entries / meta-data. ## CI - PR CI is build-only. -- Publishing is handled by a workflow that pushes a pre-release to GitHub Packages. +- Publishing is handled by `.github/workflows/publish.yml` with channel routing: + - tag `vX.Y.Z` on `master` -> NuGet.org (stable) + - tag `vX.Y.Z-rc.N` on `release/*` -> NuGet.org (pre-release) + - non-tag runs (`workflow_dispatch`) -> GitHub Packages (`X.Y.Z-preview..`) +- NuGet.org publishing uses NuGet Trusted Publishing (OIDC via `NuGet/login@v1`), no long-lived NuGet API key. + +### Required GitHub secret + +- `NUGET_USER`: your nuget.org profile username (not email), used by `NuGet/login@v1`. + +## Release examples + +- Pre-release candidate from a release branch: + - `git checkout release/1.0.0` + - `git tag v1.0.0-rc.1` + - `git push origin v1.0.0-rc.1` +- Stable release from master: + - `git checkout master` + - `git tag v1.0.0` + - `git push origin v1.0.0` diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj b/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj index b7c10f3..37d27cd 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj +++ b/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj @@ -15,7 +15,7 @@ $(NoWarn);NU5128 Kapusch.Facebook.Android Kapusch.Facebook.Android - 0.1.0 + 1.0.0 nuget-readme.md Date: Wed, 4 Mar 2026 09:56:28 +0100 Subject: [PATCH 2/5] ci: support manual version override for NuGet.org publish --- .github/workflows/publish.yml | 28 ++++++++++++++++++++-------- README.md | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 83aad2c..cf70c78 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,6 +2,11 @@ name: publish on: workflow_dispatch: + inputs: + manual_version: + description: 'Force a specific version for NuGet.org publish (e.g., 1.0.0 or 1.0.0-rc.1). If empty, defaults to auto-generated preview for GitHub Packages.' + required: false + type: string push: tags: - "v*" @@ -28,13 +33,25 @@ jobs: run: | REF="${{ github.ref }}" EVENT="${{ github.event_name }}" + MANUAL_VERSION="${{ github.event.inputs.manual_version }}" CSPROJ="src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj" BASE_VERSION=$(grep -oE '[^<]+' "$CSPROJ" | head -n 1 | sed 's///' || echo "0.1.0") - if [[ "$REF" =~ ^refs/tags/v ]]; then + if [[ -n "$MANUAL_VERSION" ]]; then + VERSION="$MANUAL_VERSION" + PUBLISH_TARGET="nuget" + echo "Manual version provided ($VERSION). Triggering NuGet.org publish." + elif [[ "$REF" =~ ^refs/tags/v ]]; then VERSION="${REF#refs/tags/v}" PUBLISH_TARGET="nuget" + else + COMMIT_SHORT=$(git rev-parse --short HEAD) + RUN_NUMBER="${{ github.run_number }}" + VERSION="${BASE_VERSION}-preview.${RUN_NUMBER}.${COMMIT_SHORT}" + PUBLISH_TARGET="github" + fi + if [[ "$PUBLISH_TARGET" == "nuget" ]]; then git fetch origin +refs/heads/*:refs/remotes/origin/* TAGGED_SHA="${{ github.sha }}" CONTAINING_BRANCHES=$(git for-each-ref --format='%(refname:short)' refs/remotes/origin --contains "$TAGGED_SHA") @@ -48,20 +65,15 @@ jobs: if [[ "$VERSION" == *-* ]]; then if [[ "$ON_RELEASE" != "true" ]]; then - echo "ERROR: Pre-release tag v$VERSION must point to a commit contained in origin/release/*" + echo "ERROR: Pre-release version $VERSION must be on origin/release/*" exit 1 fi else if [[ "$ON_MASTER" != "true" ]]; then - echo "ERROR: Stable tag v$VERSION must point to a commit contained in origin/master" + echo "ERROR: Stable version $VERSION must be on origin/master" exit 1 fi fi - else - COMMIT_SHORT=$(git rev-parse --short HEAD) - RUN_NUMBER="${{ github.run_number }}" - VERSION="${BASE_VERSION}-preview.${RUN_NUMBER}.${COMMIT_SHORT}" - PUBLISH_TARGET="github" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" diff --git a/README.md b/README.md index d84f5c8..fa86899 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Pack the NuGet: - tag `vX.Y.Z` on `master` -> NuGet.org (stable) - tag `vX.Y.Z-rc.N` on `release/*` -> NuGet.org (pre-release) - non-tag runs (`workflow_dispatch`) -> GitHub Packages (`X.Y.Z-preview..`) + - `workflow_dispatch` with `manual_version` -> NuGet.org (forced version) - NuGet.org publishing uses NuGet Trusted Publishing (OIDC via `NuGet/login@v1`), no long-lived NuGet API key. ### Required GitHub secret From cb9d592f69f80ef125033017990fd3566b0d29b6 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 14 Jul 2026 18:20:26 +0200 Subject: [PATCH 3/5] feat(share): add selectable Facebook Share SDK interop --- DependencyLocks/Android/lockstate.txt | 1 + .../Facebook/AndroidFacebookInterop.cs | 2 + .../Android/facebookinterop/build.gradle.kts | 1 + .../src/main/AndroidManifest.xml | 5 + .../FacebookInteropConstants.java | 1 + .../androidinterop/FacebookShareActivity.java | 95 +++++++++++++++++++ .../Kapusch.Facebook.Android.props | 4 + .../Kapusch.Facebook.Android.targets | 6 +- 8 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookShareActivity.java diff --git a/DependencyLocks/Android/lockstate.txt b/DependencyLocks/Android/lockstate.txt index a9b1e48..8070eb7 100644 --- a/DependencyLocks/Android/lockstate.txt +++ b/DependencyLocks/Android/lockstate.txt @@ -5,3 +5,4 @@ https://repo1.maven.org/maven2/com/facebook/android/facebook-login/18.1.3/facebo https://repo1.maven.org/maven2/com/facebook/android/facebook-core/18.1.3/facebook-core-18.1.3.aar ef480916149e078f955195981130b05746ca33b41618911e7093aa32c03d601b facebook-core-18.1.3.aar https://repo1.maven.org/maven2/com/facebook/android/facebook-common/18.1.3/facebook-common-18.1.3.aar 62adfb1cd05184065d69033a9f917709b392004f87a8aa1cc1c4f0e9fb5ca781 facebook-common-18.1.3.aar https://repo1.maven.org/maven2/com/facebook/android/facebook-bolts/18.1.3/facebook-bolts-18.1.3.aar 05c6bae0130487e63add05854a3bbd21465c06a295a2104b3948d8759536b699 facebook-bolts-18.1.3.aar +https://repo1.maven.org/maven2/com/facebook/android/facebook-share/18.1.3/facebook-share-18.1.3.aar cc3bc76fdb987ac245ddc54b37096e2afcfb438872487034027639dd4564aef7 facebook-share-18.1.3.aar diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Facebook/AndroidFacebookInterop.cs b/src/Kapusch.FacebookApisForAndroidComponents/Facebook/AndroidFacebookInterop.cs index 14cfe30..d188d2f 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Facebook/AndroidFacebookInterop.cs +++ b/src/Kapusch.FacebookApisForAndroidComponents/Facebook/AndroidFacebookInterop.cs @@ -5,12 +5,14 @@ namespace Kapusch.Facebook.Android; public static class AndroidFacebookInterop { public static string LoginActivityClassName => "com.kapusch.facebook.androidinterop.FacebookLoginActivity"; + public static string ShareActivityClassName => "com.kapusch.facebook.androidinterop.FacebookShareActivity"; public static string ExtraStatus => "kfb_status"; public static string ExtraAccessToken => "kfb_access_token"; public static string ExtraUserId => "kfb_user_id"; public static string ExtraErrorCode => "kfb_error_code"; public static string ExtraErrorMessage => "kfb_error_message"; + public static string ExtraShareImagePath => "kfb_share_image_path"; public static string LogoutAction => "com.kapusch.facebook.androidinterop.LOGOUT"; diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/build.gradle.kts b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/build.gradle.kts index 23c7221..67d5ae3 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/build.gradle.kts +++ b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/build.gradle.kts @@ -25,4 +25,5 @@ android { dependencies { implementation("com.facebook.android:facebook-login:18.1.3") + implementation("com.facebook.android:facebook-share:18.1.3") } diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/AndroidManifest.xml b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/AndroidManifest.xml index da67b30..98beabd 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/AndroidManifest.xml +++ b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/AndroidManifest.xml @@ -5,6 +5,11 @@ android:exported="false" android:launchMode="singleTask" /> + diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookInteropConstants.java b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookInteropConstants.java index 332e6f6..19afdf0 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookInteropConstants.java +++ b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookInteropConstants.java @@ -6,6 +6,7 @@ public final class FacebookInteropConstants { public static final String EXTRA_USER_ID = "kfb_user_id"; public static final String EXTRA_ERROR_CODE = "kfb_error_code"; public static final String EXTRA_ERROR_MESSAGE = "kfb_error_message"; + public static final String EXTRA_SHARE_IMAGE_PATH = "kfb_share_image_path"; public static final String LOGOUT_ACTION = "com.kapusch.facebook.androidinterop.LOGOUT"; diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookShareActivity.java b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookShareActivity.java new file mode 100644 index 0000000..aefdc27 --- /dev/null +++ b/src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/src/main/java/com/kapusch/facebook/androidinterop/FacebookShareActivity.java @@ -0,0 +1,95 @@ +package com.kapusch.facebook.androidinterop; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; + +import com.facebook.CallbackManager; +import com.facebook.FacebookCallback; +import com.facebook.FacebookException; +import com.facebook.share.Sharer; +import com.facebook.share.model.SharePhoto; +import com.facebook.share.model.SharePhotoContent; +import com.facebook.share.widget.ShareDialog; + +public final class FacebookShareActivity extends Activity { + private CallbackManager callbackManager; + private Bitmap bitmap; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String imagePath = getIntent().getStringExtra(FacebookInteropConstants.EXTRA_SHARE_IMAGE_PATH); + if (imagePath == null || imagePath.trim().isEmpty()) { + completeFailed("missing_image_path"); + return; + } + + bitmap = BitmapFactory.decodeFile(imagePath); + if (bitmap == null) { + completeFailed("image_decode_failed"); + return; + } + + callbackManager = CallbackManager.Factory.create(); + ShareDialog dialog = new ShareDialog(this); + dialog.registerCallback(callbackManager, new FacebookCallback() { + @Override + public void onSuccess(Sharer.Result result) { + complete("success", RESULT_OK, null); + } + + @Override + public void onCancel() { + complete("cancelled", RESULT_CANCELED, null); + } + + @Override + public void onError(FacebookException error) { + completeFailed(error.getClass().getSimpleName()); + } + }); + + SharePhoto photo = new SharePhoto.Builder().setBitmap(bitmap).build(); + SharePhotoContent content = new SharePhotoContent.Builder().addPhoto(photo).build(); + if (!dialog.canShow(content, ShareDialog.Mode.AUTOMATIC)) { + completeFailed("share_dialog_unavailable"); + return; + } + dialog.show(content, ShareDialog.Mode.AUTOMATIC); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (callbackManager != null) { + callbackManager.onActivityResult(requestCode, resultCode, data); + } + } + + private void completeFailed(String errorCode) { + complete("failed", RESULT_OK, errorCode); + } + + private void complete(String status, int resultCode, String errorCode) { + Intent data = new Intent(); + data.putExtra(FacebookInteropConstants.EXTRA_STATUS, status); + if (errorCode != null) { + data.putExtra(FacebookInteropConstants.EXTRA_ERROR_CODE, errorCode); + } + setResult(resultCode, data); + finish(); + } + + @Override + protected void onDestroy() { + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + super.onDestroy(); + } +} diff --git a/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.props b/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.props index 07fe0e9..efcab06 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.props +++ b/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.props @@ -1,5 +1,9 @@ + Login + <_KapuschFacebookFeaturesDelimited>;$([System.String]::Copy('$(KapuschFacebookFeatures)').Replace(' ', '')); + <_KapuschFacebookLoginEnabled>$([System.String]::Copy('$(_KapuschFacebookFeaturesDelimited)').Contains(';Login;')) + <_KapuschFacebookShareEnabled>$([System.String]::Copy('$(_KapuschFacebookFeaturesDelimited)').Contains(';Share;')) false false diff --git a/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.targets b/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.targets index a90f887..0ec3d5c 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.targets +++ b/src/Kapusch.FacebookApisForAndroidComponents/buildTransitive/Kapusch.Facebook.Android.targets @@ -32,7 +32,8 @@ - + + @@ -52,7 +53,8 @@ - + + From 0cbe0ce79e5eda099d4732a05ccc6e2f67ba3c1a Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 14 Jul 2026 18:20:30 +0200 Subject: [PATCH 4/5] docs(share): document Android feature selection --- Docs/Integration.md | 10 ++++++++++ README.md | 7 +++++-- .../nuget-readme.md | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Docs/Integration.md b/Docs/Integration.md index 743fe34..ff3cf19 100644 --- a/Docs/Integration.md +++ b/Docs/Integration.md @@ -2,6 +2,8 @@ This package injects a small Android Activity (provided by an embedded AAR) that runs the Facebook Login flow and returns its result via `Intent` extras. +Set `KapuschFacebookFeatures` to `Login` (default), `Share`, or `Login;Share`. + ## Required AndroidManifest entries You must include the required Meta/Facebook Android SDK entries in your app manifest (example only; use resources, do not hardcode secrets): @@ -26,3 +28,11 @@ Then parse the `Intent` extras: ## Sign-out Call `AndroidFacebookInterop.SendSignOutBroadcast(context)`. + +## Photo sharing + +With the `Share` feature selected, start +`AndroidFacebookInterop.ShareActivityClassName` and pass a JPEG file path using +`AndroidFacebookInterop.ExtraShareImagePath`. Read `ExtraStatus` and +`ExtraErrorCode` from the activity result. The wrapper uses `SharePhotoContent` +and never injects a message. diff --git a/README.md b/README.md index fa86899..f7bbe1f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # FacebookApisForAndroidComponents -Public OSS repository that packages **Facebook Login for Android** into a consumable .NET NuGet. +Public OSS repository that packages selected Facebook Android features into a consumable .NET NuGet. ## Package @@ -9,10 +9,13 @@ Public OSS repository that packages **Facebook Login for Android** into a consum ## What this repo ships A NuGet package that: -- provides a small managed API for starting a Facebook Login flow on Android, and +- provides managed entry points for Facebook Login and photo sharing, and - redistributes the required **Facebook Android SDK AARs** inside the `.nupkg` (classic/native packaging), - injects the AARs into consuming apps via `buildTransitive` `AndroidAarLibrary` items. +Select `KapuschFacebookFeatures=Login`, `Share`, or `Login;Share`. The default is +`Login`; only selected native AARs are injected into the consuming artifact. + ## Third-party licenses See `THIRD_PARTY_NOTICES.md`. diff --git a/src/Kapusch.FacebookApisForAndroidComponents/nuget-readme.md b/src/Kapusch.FacebookApisForAndroidComponents/nuget-readme.md index 14fbf8d..d4f83c9 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/nuget-readme.md +++ b/src/Kapusch.FacebookApisForAndroidComponents/nuget-readme.md @@ -2,6 +2,8 @@ This package embeds a small Android interop Activity and the required Facebook Android SDK AARs, and injects them into consuming apps via `buildTransitive` MSBuild. +Set `KapuschFacebookFeatures` to `Login` (default), `Share`, or `Login;Share`. + ## Notes - No secrets are included. - You must configure your AndroidManifest / resources as required by the Facebook Android SDK. From 44330acc0687d3076900d9a4c3a3e013f424c9a7 Mon Sep 17 00:00:00 2001 From: kapusch Date: Wed, 15 Jul 2026 20:18:44 +0200 Subject: [PATCH 5/5] chore(release): adopt master-only package publishing --- .github/workflows/publish.yml | 30 +++++-------------- AGENTS.md | 8 ++++- CONTRIBUTING.md | 3 ++ Docs/Release.md | 23 ++++++++++++++ README.md | 16 +++------- ...ch.FacebookApisForAndroidComponents.csproj | 2 +- 6 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 Docs/Release.md diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cf70c78..1b45c52 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -32,7 +32,6 @@ jobs: shell: bash run: | REF="${{ github.ref }}" - EVENT="${{ github.event_name }}" MANUAL_VERSION="${{ github.event.inputs.manual_version }}" CSPROJ="src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj" BASE_VERSION=$(grep -oE '[^<]+' "$CSPROJ" | head -n 1 | sed 's///' || echo "0.1.0") @@ -52,27 +51,14 @@ jobs: fi if [[ "$PUBLISH_TARGET" == "nuget" ]]; then - git fetch origin +refs/heads/*:refs/remotes/origin/* - TAGGED_SHA="${{ github.sha }}" - CONTAINING_BRANCHES=$(git for-each-ref --format='%(refname:short)' refs/remotes/origin --contains "$TAGGED_SHA") - - ON_MASTER="false" - ON_RELEASE="false" - while IFS= read -r branch; do - [[ "$branch" == "origin/master" ]] && ON_MASTER="true" - [[ "$branch" == origin/release/* ]] && ON_RELEASE="true" - done <<< "$CONTAINING_BRANCHES" - - if [[ "$VERSION" == *-* ]]; then - if [[ "$ON_RELEASE" != "true" ]]; then - echo "ERROR: Pre-release version $VERSION must be on origin/release/*" - exit 1 - fi - else - if [[ "$ON_MASTER" != "true" ]]; then - echo "ERROR: Stable version $VERSION must be on origin/master" - exit 1 - fi + git fetch origin master + if ! git merge-base --is-ancestor "${{ github.sha }}" origin/master; then + echo "ERROR: NuGet.org releases must be reachable from origin/master." + exit 1 + fi + if [[ -n "$MANUAL_VERSION" && "$REF" != "refs/heads/master" ]]; then + echo "ERROR: Manual NuGet.org releases must be dispatched from master." + exit 1 fi fi diff --git a/AGENTS.md b/AGENTS.md index 9aaa645..73941c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # Kapusch.FacebookApisForAndroidComponents — AI Working Agreement ## Goals -- Produce a reproducible Android NuGet package for Facebook Login interop. +- Produce a reproducible Android NuGet package for selectable Facebook Login and Share interop. - Do not commit secrets. ## Packaging constraints @@ -20,3 +20,9 @@ ## Safety - Do not add new dependency ingestion paths without documenting them in `README.md`. - Do not commit real app ids/secrets. + +## Branches and releases +- `master` is the only long-lived branch and the source of every NuGet.org release. +- Implement changes on short-lived branches and target `master` through a PR. Never implement directly on `release/*`. +- Both stable (`vX.Y.Z`) and prerelease (`vX.Y.Z-rc.N`) tags must reference commits reachable from `origin/master`. +- Manual runs without a version publish previews to GitHub Packages. See `Docs/Release.md` for the complete contract. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49ec310..e0d26c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,11 +32,14 @@ Pack the NuGet: ## Pull requests - Keep PRs focused and well-scoped. +- Branch from `master` and target `master`; this repository does not use long-lived `release/*` branches. - Do not commit secrets. - If you update the Facebook SDK version, update both: - `src/Kapusch.FacebookApisForAndroidComponents/Native/Android/facebookinterop/build.gradle.kts` - `DependencyLocks/Android/lockstate.txt` (URLs + SHA256) +See `Docs/Release.md` before changing versions, tags, or publishing workflows. + ## License By contributing, you agree that your contributions will be licensed under the repository license (MIT). diff --git a/Docs/Release.md b/Docs/Release.md new file mode 100644 index 0000000..6d4bebb --- /dev/null +++ b/Docs/Release.md @@ -0,0 +1,23 @@ +# Release workflow + +`master` is the only long-lived branch. Feature work uses short-lived branches and pull requests targeting `master`; this repository does not create `release/*` branches. + +## Channels + +- Manual workflow run without `manual_version`: build a preview package and publish it to GitHub Packages. +- `vX.Y.Z-rc.N` tag reachable from `origin/master`: publish that prerelease to NuGet.org. +- `vX.Y.Z` tag reachable from `origin/master`: publish that stable version to NuGet.org. +- Manual workflow run with `manual_version`: publish to NuGet.org only when the workflow runs from `master`. + +NuGet versions and Git tags are immutable. Query the official NuGet index before publishing and never move or recreate an existing tag. + +## Release sequence + +1. Fetch `origin`, start a short-lived branch from `origin/master`, and verify the worktree is clean. +2. Build the native wrapper, restore the locked AARs, pack the NuGet and inspect its selected modules. +3. Open a PR to `master` and require CI to pass. +4. Merge and fetch the resulting `origin/master` commit. +5. Create the RC or stable tag on that exact commit and push only the new tag. +6. Verify the publish workflow and the resulting NuGet package before updating consumers. + +Do not delete historical tags. Delete a temporary branch only after every retained commit is reachable from `origin/master`. diff --git a/README.md b/README.md index f7bbe1f..b0783b0 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ See `THIRD_PARTY_NOTICES.md`. - Integration: `Docs/Integration.md` - Source mode: `Docs/SourceMode.md` +- Release workflow: `Docs/Release.md` - Samples: `samples/README.md` ## Build (local) @@ -53,22 +54,13 @@ Pack the NuGet: - PR CI is build-only. - Publishing is handled by `.github/workflows/publish.yml` with channel routing: - tag `vX.Y.Z` on `master` -> NuGet.org (stable) - - tag `vX.Y.Z-rc.N` on `release/*` -> NuGet.org (pre-release) + - tag `vX.Y.Z-rc.N` on `master` -> NuGet.org (pre-release) - non-tag runs (`workflow_dispatch`) -> GitHub Packages (`X.Y.Z-preview..`) - - `workflow_dispatch` with `manual_version` -> NuGet.org (forced version) + - `workflow_dispatch` on `master` with `manual_version` -> NuGet.org (forced version) - NuGet.org publishing uses NuGet Trusted Publishing (OIDC via `NuGet/login@v1`), no long-lived NuGet API key. ### Required GitHub secret - `NUGET_USER`: your nuget.org profile username (not email), used by `NuGet/login@v1`. -## Release examples - -- Pre-release candidate from a release branch: - - `git checkout release/1.0.0` - - `git tag v1.0.0-rc.1` - - `git push origin v1.0.0-rc.1` -- Stable release from master: - - `git checkout master` - - `git tag v1.0.0` - - `git push origin v1.0.0` +See `Docs/Release.md` for the validated release sequence. Historical tags remain immutable even when obsolete branches are deleted. diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj b/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj index 37d27cd..d18f67f 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj +++ b/src/Kapusch.FacebookApisForAndroidComponents/Kapusch.FacebookApisForAndroidComponents.csproj @@ -15,7 +15,7 @@ $(NoWarn);NU5128 Kapusch.Facebook.Android Kapusch.Facebook.Android - 1.0.0 + 1.1.0 nuget-readme.md