mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-03-29 19:23:30 -04:00
247 lines
9.6 KiB
YAML
247 lines
9.6 KiB
YAML
name: Create or Promote Release
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
base_version:
|
|
description: 'Base version for the release (e.g., 2.3.0)'
|
|
required: true
|
|
channel:
|
|
description: 'The channel to create a release for or promote to'
|
|
required: true
|
|
type: choice
|
|
options:
|
|
- internal
|
|
- closed
|
|
- open
|
|
- production
|
|
dry_run:
|
|
description: 'If true, calculates the tag but does not push it or start the release'
|
|
required: true
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: read
|
|
id-token: write
|
|
attestations: write
|
|
|
|
jobs:
|
|
determine-tags:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
tag_to_process: ${{ steps.calculate_tags.outputs.tag_to_process }}
|
|
release_name: ${{ steps.calculate_tags.outputs.release_name }}
|
|
final_tag: ${{ steps.calculate_tags.outputs.final_tag }}
|
|
from_channel: ${{ steps.calculate_tags.outputs.from_channel }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
token: ${{ secrets.CROWDIN_GITHUB_TOKEN }}
|
|
|
|
- name: Calculate tags
|
|
id: calculate_tags
|
|
run: |
|
|
BASE_VERSION="${{ inputs.base_version }}"
|
|
CHANNEL="${{ inputs.channel }}"
|
|
|
|
if [[ "$CHANNEL" == "internal" ]]; then
|
|
# This is a new build, create a new internal tag
|
|
LATEST_TAG=$(git tag --list "v${BASE_VERSION}-internal.*" --sort=-v:refname | head -n 1)
|
|
|
|
if [ -z "$LATEST_TAG" ]; then
|
|
INCREMENT=1
|
|
else
|
|
INCREMENT=$(echo "$LATEST_TAG" | sed -n "s/.*-internal\.\([0-9]*\)/\1/p" | awk '{print $1+1}')
|
|
fi
|
|
|
|
NEW_TAG="v${BASE_VERSION}-internal.${INCREMENT}"
|
|
echo "Calculated new tag: $NEW_TAG"
|
|
echo "tag_to_process=$NEW_TAG" >> $GITHUB_OUTPUT
|
|
echo "release_name=$NEW_TAG" >> $GITHUB_OUTPUT
|
|
echo "final_tag=$NEW_TAG" >> $GITHUB_OUTPUT
|
|
else
|
|
# This is a promotion, find the latest tag from the previous channel to promote
|
|
FROM_CHANNEL="internal"
|
|
if [[ "$CHANNEL" == "open" ]]; then
|
|
FROM_CHANNEL="closed"
|
|
elif [[ "$CHANNEL" == "production" ]]; then
|
|
FROM_CHANNEL="open"
|
|
fi
|
|
|
|
LATEST_TAG_TO_PROMOTE=$(git tag --list "v${BASE_VERSION}-${FROM_CHANNEL}.*" --sort=-v:refname | head -n 1)
|
|
|
|
if [ -z "$LATEST_TAG_TO_PROMOTE" ]; then
|
|
echo "::error::No ${FROM_CHANNEL} release found for base version ${BASE_VERSION} to promote."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Found latest ${FROM_CHANNEL} tag to promote: $LATEST_TAG_TO_PROMOTE"
|
|
|
|
# Calculate the increment for the TARGET channel
|
|
if [[ "$CHANNEL" != "production" ]]; then
|
|
LATEST_CHANNEL_TAG=$(git tag --list "v${BASE_VERSION}-${CHANNEL}.*" --sort=-v:refname | head -n 1)
|
|
|
|
if [ -z "$LATEST_CHANNEL_TAG" ]; then
|
|
INCREMENT=1
|
|
else
|
|
INCREMENT=$(echo "$LATEST_CHANNEL_TAG" | sed -n "s/.*-${CHANNEL}\.\([0-9]*\)/\1/p" | awk '{print $1+1}')
|
|
fi
|
|
|
|
NEW_TAG="v${BASE_VERSION}-${CHANNEL}.${INCREMENT}"
|
|
else
|
|
# Production is special, it has no increment
|
|
NEW_TAG="v${BASE_VERSION}"
|
|
fi
|
|
|
|
echo "New release name will be: $NEW_TAG"
|
|
echo "Final tag will be: $NEW_TAG"
|
|
echo "from_channel=${FROM_CHANNEL}" >> $GITHUB_OUTPUT
|
|
echo "tag_to_process=${LATEST_TAG_TO_PROMOTE}" >> $GITHUB_OUTPUT
|
|
echo "release_name=${NEW_TAG}" >> $GITHUB_OUTPUT
|
|
echo "final_tag=${NEW_TAG}" >> $GITHUB_OUTPUT
|
|
fi
|
|
shell: bash
|
|
|
|
- name: Update External Assets (Firmware, Hardware, Protos)
|
|
if: ${{ !inputs.dry_run && inputs.channel == 'internal' }}
|
|
run: |
|
|
# Update Submodules (Protobufs)
|
|
echo "Updating core/proto submodule..."
|
|
git submodule update --init --remote core/proto
|
|
|
|
# Update Firmware List
|
|
firmware_file_path="app/src/main/assets/firmware_releases.json"
|
|
temp_firmware_file="/tmp/new_firmware_releases.json"
|
|
|
|
echo "Fetching latest firmware releases..."
|
|
curl -s --fail https://api.meshtastic.org/github/firmware/list > "$temp_firmware_file"
|
|
|
|
if ! jq empty "$temp_firmware_file" 2>/dev/null; then
|
|
echo "::error::Firmware API returned invalid JSON data. Aborting."
|
|
exit 1
|
|
else
|
|
if [ ! -f "$firmware_file_path" ] || ! jq --sort-keys . "$temp_firmware_file" | diff -q - <(jq --sort-keys . "$firmware_file_path"); then
|
|
echo "Changes detected in firmware list or local file missing. Updating $firmware_file_path."
|
|
cp "$temp_firmware_file" "$firmware_file_path"
|
|
else
|
|
echo "No changes detected in firmware list."
|
|
fi
|
|
fi
|
|
|
|
# Update Hardware List
|
|
hardware_file_path="app/src/main/assets/device_hardware.json"
|
|
temp_hardware_file="/tmp/new_device_hardware.json"
|
|
|
|
echo "Fetching latest device hardware data..."
|
|
curl -s --fail https://api.meshtastic.org/resource/deviceHardware > "$temp_hardware_file"
|
|
|
|
if ! jq empty "$temp_hardware_file" 2>/dev/null; then
|
|
echo "::error::Hardware API returned invalid JSON data. Aborting."
|
|
exit 1
|
|
else
|
|
if [ ! -f "$hardware_file_path" ] || ! jq --sort-keys . "$temp_hardware_file" | diff -q - <(jq --sort-keys . "$hardware_file_path"); then
|
|
echo "Changes detected in hardware list or local file missing. Updating $hardware_file_path."
|
|
cp "$temp_hardware_file" "$hardware_file_path"
|
|
else
|
|
echo "No changes detected in hardware list."
|
|
fi
|
|
fi
|
|
|
|
- name: Sync with Crowdin
|
|
if: ${{ !inputs.dry_run && inputs.channel == 'internal' }}
|
|
uses: crowdin/github-action@v2
|
|
with:
|
|
base_url: 'https://meshtastic.crowdin.com/api/v2'
|
|
config: 'crowdin.yml'
|
|
crowdin_branch_name: 'main'
|
|
upload_sources: true
|
|
upload_sources_args: '--preserve-hierarchy'
|
|
upload_translations: false
|
|
download_translations: true
|
|
download_translations_args: '--preserve-hierarchy'
|
|
create_pull_request: false
|
|
push_translations: false
|
|
push_sources: false
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
|
|
|
- name: Commit Release Assets (Translations, Data, Config)
|
|
if: ${{ !inputs.dry_run && inputs.channel == 'internal' }}
|
|
env:
|
|
FINAL_TAG: ${{ steps.calculate_tags.outputs.final_tag }}
|
|
run: |
|
|
# Calculate Version Code
|
|
OFFSET=$(grep '^VERSION_CODE_OFFSET=' config.properties | cut -d'=' -f2)
|
|
COMMIT_COUNT=$(git rev-list --count HEAD)
|
|
# +1 because we are about to add a commit
|
|
VERSION_CODE=$((COMMIT_COUNT + OFFSET + 1))
|
|
|
|
echo "Calculated Version Code: $VERSION_CODE"
|
|
|
|
# Update VERSION_NAME_BASE in config.properties
|
|
sed -i "s/^VERSION_NAME_BASE=.*/VERSION_NAME_BASE=${{ inputs.base_version }}/" config.properties
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
|
|
# Add updated data files
|
|
git add config.properties
|
|
git add app/src/main/assets/firmware_releases.json || true
|
|
git add app/src/main/assets/device_hardware.json || true
|
|
git add core/proto || true
|
|
|
|
# Add updated translations (fastlane metadata and strings)
|
|
git add fastlane/metadata/android || true
|
|
git add "**/strings.xml" || true
|
|
|
|
# Only commit if there are changes
|
|
if ! git diff --cached --quiet; then
|
|
git commit -m "chore(release): prepare $FINAL_TAG [skip ci]
|
|
|
|
- Bump base version to ${{ inputs.base_version }}
|
|
- Sync translations and assets"
|
|
git push origin HEAD:${{ github.ref_name }}
|
|
else
|
|
echo "No changes to commit."
|
|
fi
|
|
shell: bash
|
|
|
|
- name: Create and Push Release Tag
|
|
if: ${{ !inputs.dry_run && inputs.channel == 'internal' }}
|
|
env:
|
|
FINAL_TAG: ${{ steps.calculate_tags.outputs.final_tag }}
|
|
run: |
|
|
echo "Tagging and pushing release: $FINAL_TAG"
|
|
git tag "$FINAL_TAG"
|
|
git push origin "$FINAL_TAG"
|
|
shell: bash
|
|
|
|
call-release-workflow:
|
|
if: ${{ !inputs.dry_run && inputs.channel == 'internal' }}
|
|
needs: determine-tags
|
|
uses: ./.github/workflows/release.yml
|
|
with:
|
|
tag_name: ${{ needs.determine-tags.outputs.final_tag }}
|
|
channel: ${{ inputs.channel }}
|
|
base_version: ${{ inputs.base_version }}
|
|
secrets: inherit
|
|
|
|
call-promote-workflow:
|
|
if: ${{ !inputs.dry_run && inputs.channel != 'internal' }}
|
|
needs: determine-tags
|
|
uses: ./.github/workflows/promote.yml
|
|
with:
|
|
tag_name: ${{ needs.determine-tags.outputs.tag_to_process }}
|
|
release_name: ${{ needs.determine-tags.outputs.release_name }}
|
|
final_tag: ${{ needs.determine-tags.outputs.final_tag }}
|
|
channel: ${{ inputs.channel }}
|
|
base_version: ${{ inputs.base_version }}
|
|
from_channel: ${{ needs.determine-tags.outputs.from_channel }}
|
|
secrets: inherit
|