diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 4b7588ebf..000000000 --- a/.dockerignore +++ /dev/null @@ -1,6 +0,0 @@ -uni/.packages -uni/.flutter-plugins -uni/.metadata -uni/*.log -uni/.vscode -uni/.idea \ No newline at end of file diff --git a/.github/workflows/app_version_integrity.yaml b/.github/workflows/app_version_integrity.yaml deleted file mode 100644 index 15da3831d..000000000 --- a/.github/workflows/app_version_integrity.yaml +++ /dev/null @@ -1,18 +0,0 @@ -on: pull_request - -jobs: - app_version_integrity: - name: "Version integrity" - runs-on: ubuntu-latest - env: - APP_VERSION_PATH: "packages/uni_app/app_version.txt" - steps: - - uses: actions/checkout@v4 - - - name: Fetch origin target branch - run: | - git fetch origin ${{ github.base_ref }} - - - name: Ensure app_version was not changed manually or was created just now - run: | - (! git cat-file -e FETCH_HEAD:${{ env.APP_VERSION_PATH }} && git cat-file -e HEAD:${{env.APP_VERSION_PATH}}) || git diff --quiet FETCH_HEAD:${{ env.APP_VERSION_PATH }} HEAD:${{ env.APP_VERSION_PATH }} || (echo "App version file was modified manually. Skipping deploy" && exit 1) diff --git a/.github/workflows/beta.yaml b/.github/workflows/beta.yaml new file mode 100644 index 000000000..9791031ec --- /dev/null +++ b/.github/workflows/beta.yaml @@ -0,0 +1,40 @@ +name: Beta + +on: + push: + branches: [ develop ] + +concurrency: + group: beta + cancel-in-progress: false + +jobs: + bump: + name: Bump Version + runs-on: ubuntu-latest + outputs: + new_version: ${{ steps.bump.outputs.NEW_VERSION }} + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.NIAEFEUPBOT_PAT }} + + - name: Bump Version + id: bump + run: ./scripts/bump_version.sh packages/uni_app develop + + - name: Commit & Push + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "chore: bump build number to ${{ steps.bump.outputs.NEW_VERSION }} [skip ci]" + branch: develop + file_pattern: 'packages/uni_app/app_version.txt packages/uni_app/pubspec.yaml' + + deploy_beta: + name: Deploy to Beta + needs: bump + uses: ./.github/workflows/deploy.yml + with: + environment: staging + lane: beta + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml new file mode 100644 index 000000000..0b893fee2 --- /dev/null +++ b/.github/workflows/checks.yaml @@ -0,0 +1,139 @@ +name: Pull Request Checks + +on: + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] + push: + branches: [master, develop] + +env: + JAVA_VERSION: 21.x + WORKING_DIR: packages/uni_app + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + integrity_check: + name: Version Integrity Check + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate Version Integrity + run: | + FILE_PATH="${{ env.WORKING_DIR }}/app_version.txt" + git fetch origin ${{ github.base_ref }} + if ! git diff --quiet origin/${{ github.base_ref }} -- $FILE_PATH; then + echo "Error: Manual changes to $FILE_PATH are not allowed." + echo "Versioning is handled automatically by the CD pipeline." + exit 1 + fi + + format: + name: Format + runs-on: ubuntu-latest + needs: integrity_check + defaults: + run: + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version-file: ${{ env.WORKING_DIR }}/pubspec.yaml + cache: true + + - name: Install Dependencies + run: flutter pub get + + - name: Check Formatting + run: | + dart format $(find . -type f -name "*.dart" -a -not -name "*.g.dart" -a -not -name "*.mocks.dart") --set-exit-if-changed + + lint: + name: Lint + runs-on: ubuntu-latest + needs: integrity_check + defaults: + run: + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: 'zulu' + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version-file: ${{ env.WORKING_DIR }}/pubspec.yaml + cache: true + + - name: Install Dependencies + run: flutter pub get + + - name: Analyze + run: flutter analyze . + + test: + name: Test + runs-on: ubuntu-latest + needs: integrity_check + defaults: + run: + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: 'zulu' + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version-file: ${{ env.WORKING_DIR }}/pubspec.yaml + cache: true + + - name: Install Dependencies + run: flutter pub get + + - name: Run Tests + run: flutter test --coverage + + - name: Upload Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + + label_check: + name: Release Label Check + if: github.event_name == 'pull_request' && github.base_ref == 'master' + runs-on: ubuntu-latest + steps: + - name: Verify Release Label + run: | + labels="${{ join(github.event.pull_request.labels.*.name, ',') }}" + count=0 + if [[ $labels == *"release:major"* ]]; then count=$((count+1)); fi + if [[ $labels == *"release:minor"* ]]; then count=$((count+1)); fi + if [[ $labels == *"release:patch"* ]]; then count=$((count+1)); fi + + if [ $count -ne 1 ]; then + echo "Error: PR to master must have exactly one label: release:major, release:minor, or release:patch" + exit 1 + fi diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index fac76818e..b8f3d005d 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -1,181 +1,136 @@ -on: - push: - branches: [master, develop] - workflow_dispatch: +name: Deploy -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} +on: + workflow_call: + inputs: + environment: + required: true + type: string + lane: + required: true + type: string + secrets: + NIAEFEUPBOT_PAT: + required: true + + IOS_P12_BASE64: + required: true + IOS_P12_PASSWORD: + required: true + IOS_PROVISIONING_PROFILE_BASE64: + required: true + IOS_BUNDLE_ID: + required: true + APP_STORE_CONNECT_API_KEY_KEY_ID: + required: true + APP_STORE_CONNECT_API_KEY_ISSUER_ID: + required: true + APP_STORE_CONNECT_API_KEY_CONTENT: + required: true + + GOOGLE_SERVICE_ACCOUNT_JSON: + required: true + ANDROID_KEYSTORE_BASE64: + required: true + ANDROID_KEYSTORE_PASSWORD: + required: true + ANDROID_KEY_ALIAS: + required: true + ANDROID_KEY_PASSWORD: + required: true -name: Deploy Action jobs: - build: - permissions: - actions: "write" - name: "Bump version and Build App Bundle" - runs-on: ubuntu-latest - environment: - name: ${{ github.ref_name }} - env: - PROPERTIES_PATH: android/key.properties - JAVA_VERSION: 21.x - APP_VERSION_PATH: app_version.txt - PUBSPEC_PATH: pubspec.yaml + deploy: + name: Deploy to ${{ inputs.lane }} + runs-on: macos-latest + environment: ${{ inputs.environment }} + timeout-minutes: 45 defaults: run: working-directory: ./packages/uni_app + steps: - uses: actions/checkout@v4 - with: - token: ${{ secrets.NIAEFEUPBOT_PAT }} - fetch-depth: 0 - - name: Get develop hash - if: github.ref == 'refs/heads/master' - # We get the master hash by assuming that the last commit is always a - # merge commit. This is assured by requiring pull requests. You should NOT - # use rebase or squash merges onto the master branch. - run: | - git fetch origin develop - git pull origin master - echo "DEVELOP_HASH=$(git rev-parse origin/develop)" >> $GITHUB_ENV - echo "MASTER_HASH=$(git rev-parse origin/master^2)" >> $GITHUB_ENV - - - name: Get latest version (develop) - if: github.ref != 'refs/heads/master' - uses: LuisDuarte1/google-play-latest-version-code@v0.2.1 - id: latest-beta-version + - uses: actions/setup-java@v3 with: - google_service_account_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }} - package_name: ${{ secrets.ANDROID_PACKAGE_NAME }} - track: "beta" - - - name: Get latest production version - uses: LuisDuarte1/google-play-latest-version-code@v0.2.1 - id: latest-production-version + distribution: 'zulu' + java-version: '17' + cache: 'gradle' + + - uses: subosito/flutter-action@v2 with: - google_service_account_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }} - package_name: ${{ secrets.ANDROID_PACKAGE_NAME }} - track: "production" - - - name: Bump beta version - uses: LuisDuarte1/semver-bump-environment@v1.0.0 - if: github.ref != 'refs/heads/master' - id: bump-beta-version + channel: 'stable' + cache: true + + - uses: ruby/setup-ruby@v1 with: - current_environment: staging - production_version: ${{ steps.latest-production-version.outputs.latest_version_name }} - staging_version: ${{ steps.latest-beta-version.outputs.latest_version_name }} - bump_type: prerelease + ruby-version: '3.2' + bundler-cache: true + working-directory: ./packages/uni_app - - name: Bump prod version (from develop) - uses: LuisDuarte1/semver-bump-environment@v1.0.0 - if: github.ref == 'refs/heads/master' && env.MASTER_HASH == env.DEVELOP_HASH - id: bump-prod-major-version - with: - current_environment: production - production_version: ${{ steps.latest-production-version.outputs.latest_version_name }} - bump_type: minor + - name: Dependencies + run: flutter pub get - - name: Bump prod version (patch) - uses: LuisDuarte1/semver-bump-environment@v1.0.0 - if: github.ref == 'refs/heads/master' && env.MASTER_HASH != env.DEVELOP_HASH - id: bump-prod-patch-version + - name: Cache iOS Pods + uses: actions/cache@v3 with: - current_environment: production - production_version: ${{ steps.latest-production-version.outputs.latest_version_name }} - bump_type: patch - - - name: Combine output and write new version into file + path: packages/uni_app/ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('packages/uni_app/ios/Podfile.lock') }} + restore-keys: ${{ runner.os }}-pods- + + - name: Setup Android Signing + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + GOOGLE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }} run: | - export NEW_VERSION_NAME=${{ - (steps.bump-beta-version.outcome == 'success' && steps.bump-beta-version.outputs.new_version) || - (steps.bump-prod-minor-version.outcome == 'success' && steps.bump-prod-minor-version.outputs.new_version) || - (steps.bump-prod-patch-version.outcome == 'success' && steps.bump-prod-patch-version.outputs.new_version) || - (steps.bump-prod-major-version.outcome == 'success' && steps.bump-prod-major-version.outputs.new_version) - }} - echo "$NEW_VERSION_NAME+$((${{steps.latest-production-version.outputs.latest_version_code}} + 1))" > ${{env.APP_VERSION_PATH}} - - - name: Copy app version to pubspec - run: cat ${{ env.APP_VERSION_PATH }} | tr -d '\n' | perl -i -pe 's/^(version:\s+)(.+)$/$1.()/e' ${{ env.PUBSPEC_PATH }} - - - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: "Bump app version [no ci]" - - - uses: actions/setup-java@v4 - with: - java-version: ${{env.JAVA_VERSION}} - distribution: "zulu" - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version-file: packages/uni_app/pubspec.yaml - cache: true - - - name: Download Android keystore - run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > /tmp/key.jks - - - name: Create key.properties + echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > android/app/upload-keystore.jks + + echo "storePassword=$ANDROID_KEYSTORE_PASSWORD" > android/key.properties + echo "keyPassword=$ANDROID_KEY_PASSWORD" >> android/key.properties + echo "keyAlias=$ANDROID_KEY_ALIAS" >> android/key.properties + echo "storeFile=upload-keystore.jks" >> android/key.properties + + echo "$GOOGLE_SERVICE_ACCOUNT_JSON" > android/fastlane/api.json + + - name: Setup iOS Signing + env: + P12_BASE64: ${{ secrets.IOS_P12_BASE64 }} + PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }} run: | - rm -f -- ${{env.PROPERTIES_PATH}} - touch ${{env.PROPERTIES_PATH}} - echo "storeFile=/tmp/key.jks" >> ${{env.PROPERTIES_PATH}} - echo "storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" >> ${{env.PROPERTIES_PATH}} - echo "keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}" >> ${{env.PROPERTIES_PATH}} - echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" >> ${{env.PROPERTIES_PATH}} - - - name: Create .env file - run: echo "${{vars.UNI_ENV_FILE}}" > ./assets/env/.env - - - name: Build Android App Bundle - run: | - flutter pub get - flutter build appbundle - - - name: Upload App Bundle - uses: actions/upload-artifact@v4 - with: - name: appbundle - if-no-files-found: error - path: packages/uni_app/build/app/outputs/bundle/release/app-release.aab - - deploy_play_store: - name: "Deploy to Google Play Store" - runs-on: ubuntu-latest - needs: [build] - steps: - - uses: actions/checkout@v4 - - name: Get App Bundle - uses: actions/download-artifact@v4 - with: - name: appbundle - - - name: Release app to beta track - if: github.ref == 'refs/heads/develop' - uses: r0adkll/upload-google-play@v1 - with: - serviceAccountJsonPlainText: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }} - packageName: ${{ secrets.ANDROID_PACKAGE_NAME }} - releaseFiles: app-release.aab - whatsNewDirectory: whatsnew - track: beta - status: completed - - - name: Release app to production track - if: github.ref == 'refs/heads/master' - uses: r0adkll/upload-google-play@v1 - with: - serviceAccountJsonPlainText: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }} - packageName: ${{ secrets.ANDROID_PACKAGE_NAME }} - releaseFiles: app-release.aab - whatsNewDirectory: whatsnew - track: production - status: completed - - - name: Propagate version to develop - if: github.ref == 'refs/heads/master' + mkdir -p ios/certs + echo "$P12_BASE64" | base64 --decode > ios/certs/distribution.p12 + echo "$PROFILE_BASE64" | base64 --decode > ios/certs/app.mobileprovision + + - name: Deploy + env: + IOS_P12_PATH: "certs/distribution.p12" + IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }} + IOS_PROFILE_PATH: "certs/app.mobileprovision" + APP_BUNDLE_ID: ${{ secrets.IOS_BUNDLE_ID }} + + ASC_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }} + ASC_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }} + ASC_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }} run: | - echo '${{ secrets.NIAEFEUPBOT_PAT }}' | gh auth login --with-token - gh workflow run 'Deploy Action' --ref develop + cd android + bundle exec fastlane ${{ inputs.lane }} & + PID_ANDROID=$! + + cd ../ios + bundle exec fastlane ${{ inputs.lane }} & + PID_IOS=$! + + wait $PID_ANDROID + ANDROID_STATUS=$? + + wait $PID_IOS + IOS_STATUS=$? + + if [ $ANDROID_STATUS -ne 0 ] || [ $IOS_STATUS -ne 0 ]; then + echo "One or more deployments failed." + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/format_lint_test.yaml b/.github/workflows/format_lint_test.yaml deleted file mode 100644 index 21c1270b9..000000000 --- a/.github/workflows/format_lint_test.yaml +++ /dev/null @@ -1,81 +0,0 @@ -on: - pull_request: - push: - branches: [master, develop] - -env: - JAVA_VERSION: 21.x - -jobs: - format: - name: Format - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version-file: packages/uni_app/pubspec.yaml - cache: true - - - run: flutter pub get - - - run: dart format $(find . -type f -name "*.dart" -a -not -name "*.g.dart" -a -not -name "*.mocks.dart") --set-exit-if-changed - - lint: - name: Lint - runs-on: ubuntu-latest - needs: format - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - uses: actions/setup-java@v4 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: zulu - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version-file: packages/uni_app/pubspec.yaml - cache: true - - - run: flutter pub get - - - run: | - flutter analyze . - - test: - name: Test - runs-on: ubuntu-latest - needs: lint - defaults: - run: - working-directory: ./packages/uni_app - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: zulu - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version-file: packages/uni_app/pubspec.yaml - cache: true - - - name: Test with coverage - run: flutter test --coverage - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true diff --git a/.github/workflows/production.yaml b/.github/workflows/production.yaml new file mode 100644 index 000000000..dadfcb6f8 --- /dev/null +++ b/.github/workflows/production.yaml @@ -0,0 +1,89 @@ +name: Production + +on: + pull_request: + branches: [ master ] + types: [closed] + +concurrency: + group: production-${{ github.ref }} + cancel-in-progress: false + +jobs: + bump: + name: Bump Version + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: master + token: ${{ secrets.NIAEFEUPBOT_PAT }} + + - name: Determine Release Type + id: type + run: | + labels="${{ join(github.event.pull_request.labels.*.name, ',') }}" + if [[ $labels == *"release:major"* ]]; then echo "level=major" >> $GITHUB_OUTPUT; fi + if [[ $labels == *"release:minor"* ]]; then echo "level=minor" >> $GITHUB_OUTPUT; fi + if [[ $labels == *"release:patch"* ]]; then echo "level=patch" >> $GITHUB_OUTPUT; fi + + - name: Bump Version + id: bump + run: ./scripts/bump_version.sh packages/uni_app production ${{ steps.type.outputs.level }} + + - name: Commit & Push + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "chore(release): ${{ steps.bump.outputs.NEW_VERSION }} [skip ci]" + branch: master + tagging_message: "v${{ steps.bump.outputs.NEW_VERSION }}" + file_pattern: 'packages/uni_app/app_version.txt packages/uni_app/pubspec.yaml' + + + deploy_prod: + name: Deploy to Production + needs: bump + uses: ./.github/workflows/deploy.yml + with: + environment: production + lane: production + secrets: inherit + + sync_develop: + name: Sync develop with master + needs: deploy_prod + runs-on: ubuntu-latest + concurrency: + group: production-sync-${{ github.ref }} + cancel-in-progress: true + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Rebase develop onto master + run: | + set -euo pipefail + + git fetch origin + + git checkout develop + git reset --hard origin/develop + + git rebase origin/master || { + echo "Rebase conflict detected!" + echo "Manual resolution required." + exit 1 + } + + git push --force-with-lease origin develop + + echo "✅ Develop successfully rebased onto master" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e42768562..000000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM cirrusci/flutter:3.3.2 - -WORKDIR /app - -COPY ./app_feup/ . - -RUN flutter pub get - -CMD [ "sh", "-c" , "flutter analyze --no-pub --preamble . && flutter test"] diff --git a/packages/uni_app/Gemfile b/packages/uni_app/Gemfile new file mode 100644 index 000000000..7a118b49b --- /dev/null +++ b/packages/uni_app/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/packages/uni_app/Gemfile.lock b/packages/uni_app/Gemfile.lock new file mode 100644 index 000000000..3303f297b --- /dev/null +++ b/packages/uni_app/Gemfile.lock @@ -0,0 +1,234 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + abbrev (0.1.2) + addressable (2.8.8) + public_suffix (>= 2.0.2, < 8.0) + artifactory (3.0.17) + atomos (0.1.3) + aws-eventstream (1.4.0) + aws-partitions (1.1209.0) + aws-sdk-core (3.241.4) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sdk-kms (1.121.0) + aws-sdk-core (~> 3, >= 3.241.4) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.212.0) + aws-sdk-core (~> 3, >= 3.241.4) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + base64 (0.2.0) + benchmark (0.5.0) + bigdecimal (4.0.1) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + csv (3.3.5) + declarative (0.0.20) + digest-crc (0.7.0) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.6.20240107) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.112.0) + faraday (1.8.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + multipart-post (>= 1.2, < 3) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.8) + faraday (>= 0.8.0) + http-cookie (>= 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.1) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-net_http (1.0.2) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday_middleware (1.2.1) + faraday (~> 1.0) + fastimage (2.4.0) + fastlane (2.231.1) + CFPropertyList (>= 2.3, < 4.0.0) + abbrev (~> 0.1.2) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + base64 (~> 0.2.0) + benchmark (>= 0.1.0) + bundler (>= 1.17.3, < 5.0.0) + colored (~> 1.2) + commander (~> 4.6) + csv (~> 3.3) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + http-cookie (~> 1.0.5) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + logger (>= 1.6, < 2.0) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (>= 2.0.0, < 3.0.0) + mutex_m (~> 0.3.0) + naturally (~> 2.2) + nkf (~> 0.2.0) + optparse (>= 0.1.1, < 1.0.0) + ostruct (>= 0.1.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.5) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-sirp (1.0.0) + sysrandom (~> 1.0) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.54.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.3) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.8.0) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.5.0) + google-cloud-storage (1.47.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.8.1) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.8) + domain_name (~> 0.5) + httpclient (2.9.0) + mutex_m + jmespath (1.6.2) + json (2.18.0) + jwt (2.10.2) + base64 + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + multi_json (1.19.1) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.0) + naturally (2.3.0) + nkf (0.2.0) + optparse (0.8.1) + os (1.1.4) + ostruct (0.6.3) + plist (3.7.2) + public_suffix (7.0.2) + rake (13.3.1) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.4.4) + rouge (3.28.0) + ruby2_keywords (0.0.5) + rubyzip (2.4.1) + security (0.1.5) + signet (0.21.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 4.0) + multi_json (~> 1.10) + simctl (1.6.10) + CFPropertyList + naturally + sysrandom (1.0.5) + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.2) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (2.6.0) + word_wrap (1.0.0) + xcodeproj (1.27.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + rexml (>= 3.3.6, < 4.0) + xcpretty (0.4.1) + rouge (~> 3.28.0) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + fastlane + +BUNDLED WITH + 4.0.3 diff --git a/packages/uni_app/android/fastlane/Appfile b/packages/uni_app/android/fastlane/Appfile new file mode 100644 index 000000000..ba572264c --- /dev/null +++ b/packages/uni_app/android/fastlane/Appfile @@ -0,0 +1,2 @@ +json_key_file("fastlane/api.json") +package_name("pt.up.fe.ni.uni") \ No newline at end of file diff --git a/packages/uni_app/android/fastlane/Fastfile b/packages/uni_app/android/fastlane/Fastfile new file mode 100644 index 000000000..b861be943 --- /dev/null +++ b/packages/uni_app/android/fastlane/Fastfile @@ -0,0 +1,33 @@ +default_platform(:android) + +platform :android do + + desc "Beta Deployment (Internal Track)" + lane :beta do + Dir.chdir("..") do + sh "flutter build appbundle --release" + end + + upload_to_play_store( + track: 'internal', + release_status: 'draft', + aab: '../build/app/outputs/bundle/release/app-release.aab', + skip_upload_metadata: true, + skip_upload_images: true, + skip_upload_screenshots: true + ) + end + + desc "Production Deployment" + lane :production do + Dir.chdir("..") do + sh "flutter build appbundle --release" + end + + upload_to_play_store( + track: 'production', + release_status: 'draft', + aab: '../build/app/outputs/bundle/release/app-release.aab' + ) + end +end \ No newline at end of file diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 2fee45a22..ca52240c8 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -2.3.0-beta.6+468 +2.2.0+468 diff --git a/packages/uni_app/ios/fastlane/Appfile b/packages/uni_app/ios/fastlane/Appfile new file mode 100644 index 000000000..fd20debe6 --- /dev/null +++ b/packages/uni_app/ios/fastlane/Appfile @@ -0,0 +1,2 @@ +app_identifier("pt.up.fe.ni.uni") +apple_id("ni@aefeup.pt") \ No newline at end of file diff --git a/packages/uni_app/ios/fastlane/Fastfile b/packages/uni_app/ios/fastlane/Fastfile new file mode 100644 index 000000000..d63056e48 --- /dev/null +++ b/packages/uni_app/ios/fastlane/Fastfile @@ -0,0 +1,76 @@ +default_platform(:ios) + +platform :ios do + before_all do + if is_ci + setup_manual_signing + end + end + + desc "Setup Manual Signing (CI Only)" + lane :setup_manual_signing do + create_keychain( + name: "ci_keychain", + password: "temp_password", + default_keychain: true, + unlock: true, + timeout: 3600, + lock_when_sleeps: false + ) + + import_certificate( + certificate_path: ENV["IOS_P12_PATH"], + certificate_password: ENV["IOS_P12_PASSWORD"], + keychain_name: "ci_keychain", + keychain_password: "temp_password" + ) + + install_provisioning_profile( + profile_path: ENV["IOS_PROFILE_PATH"] + ) + + update_code_signing_settings( + use_automatic_signing: false, + targets: ["Runner"], + path: "Runner.xcodeproj", + bundle_identifier: ENV["APP_BUNDLE_ID"], + profile_name: "AppStore Profile", + code_sign_identity: "Apple Distribution" + ) + end + + desc "Beta Deployment (TestFlight)" + lane :beta do + + build_app( + workspace: "Runner.xcworkspace", + scheme: "Runner", + export_method: "app-store", + clean: true + ) + + upload_to_testflight( + skip_waiting_for_build_processing: true, + skip_submission: true + ) + end + + desc "Production Deployment (App Store)" + lane :production do + + build_app( + workspace: "Runner.xcworkspace", + scheme: "Runner", + export_method: "app-store", + clean: true + ) + + upload_to_app_store( + force: true, + submit_for_review: false, + reject_if_possible: true, + skip_metadata: false, + skip_screenshots: false + ) + end +end \ No newline at end of file diff --git a/scripts/bump_version.sh b/scripts/bump_version.sh new file mode 100644 index 000000000..b1d2450a1 --- /dev/null +++ b/scripts/bump_version.sh @@ -0,0 +1,56 @@ +#!/bin/bash +set -e + +# Usage: ./bump_version.sh [TYPE] + +PROJECT_DIR=$1 +MODE=$2 +TYPE=${3:-patch} + +if [ -z "$PROJECT_DIR" ]; then + echo "Error: Project directory argument missing." + exit 1 +fi + +VERSION_FILE="$PROJECT_DIR/app_version.txt" +PUBSPEC_FILE="$PROJECT_DIR/pubspec.yaml" + +if [ ! -f "$VERSION_FILE" ]; then + echo "Error: $VERSION_FILE not found." + exit 1 +fi + +FULL_VERSION=$(cat "$VERSION_FILE") + +if [[ $FULL_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)\+([0-9]+)$ ]]; then + MAJOR="${BASH_REMATCH[1]}" + MINOR="${BASH_REMATCH[2]}" + PATCH="${BASH_REMATCH[3]}" + BUILD="${BASH_REMATCH[4]}" +else + echo "Error: Invalid format $FULL_VERSION. Expected X.Y.Z+BUILD" + exit 1 +fi + +NEW_BUILD=$((BUILD + 1)) + +if [ "$MODE" == "production" ]; then + if [ "$TYPE" == "major" ]; then + MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 + elif [ "$TYPE" == "minor" ]; then + MINOR=$((MINOR + 1)); PATCH=0 + else + PATCH=$((PATCH + 1)) + fi +fi + +NEW_VERSION="$MAJOR.$MINOR.$PATCH+$NEW_BUILD" +echo "Bumping: $FULL_VERSION -> $NEW_VERSION" + +echo "$NEW_VERSION" > "$VERSION_FILE" + +sed -i.bak -E "s/^version: .*/version: $NEW_VERSION/" "$PUBSPEC_FILE" && rm "${PUBSPEC_FILE}.bak" + +if [ -n "$GITHUB_OUTPUT" ]; then + echo "NEW_VERSION=$NEW_VERSION" >> "$GITHUB_OUTPUT" +fi \ No newline at end of file