diff --git a/CODEOWNERS b/.github/CODEOWNERS similarity index 100% rename from CODEOWNERS rename to .github/CODEOWNERS diff --git a/.github/actions/build-xcframework/action.yml b/.github/actions/build-xcframework/action.yml new file mode 100644 index 0000000..55afdf8 --- /dev/null +++ b/.github/actions/build-xcframework/action.yml @@ -0,0 +1,52 @@ +name: Build XCFramework +description: Build XCFramework for iOS and iOS Simulator + +inputs: + project_name: + description: Name of the Xcode project or scheme + required: true + +outputs: + xcframework_path: + description: Final path to the generated XCFramework + value: ${{ steps.build.outputs.xcframework_path }} + +runs: + using: "composite" + steps: + - name: Build XCFramework + id: build + shell: bash + run: | + set -euo pipefail + + PROJECT_NAME="${{ inputs.project_name }}" + BUILD_DIR="./build" + + echo "šŸ› ļø Building XCFramework..." + + xcodebuild archive \ + -scheme "$PROJECT_NAME" \ + -configuration Release \ + -destination 'generic/platform=iOS Simulator' \ + -archivePath "$BUILD_DIR/${PROJECT_NAME}.framework-iphonesimulator.xcarchive" \ + SKIP_INSTALL=NO \ + BUILD_LIBRARIES_FOR_DISTRIBUTION=YES | xcbeautify + + xcodebuild archive \ + -scheme "$PROJECT_NAME" \ + -configuration Release \ + -destination 'generic/platform=iOS' \ + -archivePath "$BUILD_DIR/${PROJECT_NAME}.framework-iphoneos.xcarchive" \ + SKIP_INSTALL=NO \ + BUILD_LIBRARIES_FOR_DISTRIBUTION=YES | xcbeautify + + XCFRAMEWORK_PATH="$BUILD_DIR/${PROJECT_NAME}.xcframework" + + xcodebuild -create-xcframework \ + -framework "$BUILD_DIR/${PROJECT_NAME}.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" \ + -framework "$BUILD_DIR/${PROJECT_NAME}.framework-iphoneos.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" \ + -output "$XCFRAMEWORK_PATH" + + echo "āœ… XCFramework built successfully" + echo "xcframework_path=$XCFRAMEWORK_PATH" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/get-project-version/action.yml b/.github/actions/get-project-version/action.yml new file mode 100644 index 0000000..5ee6a08 --- /dev/null +++ b/.github/actions/get-project-version/action.yml @@ -0,0 +1,45 @@ +name: Get Project Version +description: Extracts MARKETING_VERSION from a .pbxproj file + +inputs: + project_name: + description: Name of the Xcode project (without .xcodeproj) + required: false + pbxproj_path: + description: Path to the project.pbxproj file (overrides project_name if provided) + required: false + +outputs: + version: + description: The extracted project version + value: ${{ steps.extract.outputs.version }} + +runs: + using: "composite" + steps: + - name: Extract current project version + id: extract + shell: bash + run: | + set -euo pipefail + + # Determine the pbxproj path + if [[ -n "${{ inputs.pbxproj_path }}" ]]; then + PBXPROJ="${{ inputs.pbxproj_path }}" + elif [[ -n "${{ inputs.project_name }}" ]]; then + PBXPROJ="${{ inputs.project_name }}.xcodeproj/project.pbxproj" + else + echo "āŒ Either 'project_name' or 'pbxproj_path' must be provided." + exit 1 + fi + + # Check if the pbxproj file exists + if [[ ! -f "$PBXPROJ" ]]; then + echo "āŒ Project file not found: $PBXPROJ" + exit 1 + fi + + echo "šŸ“¦ Extracting current MARKETING_VERSION from $PBXPROJ..." + VERSION=$(grep -m1 'MARKETING_VERSION =' "$PBXPROJ" | sed -E 's/.*MARKETING_VERSION = ([^;]+);/\1/' | xargs) + echo "šŸ”¢ Current version: $VERSION" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml new file mode 100644 index 0000000..b300ab2 --- /dev/null +++ b/.github/actions/install-dependencies/action.yml @@ -0,0 +1,50 @@ +name: Install Dependencies +description: Checks for Homebrew and installs any missing CLI tools and Ruby gems + +inputs: + tools: + description: Space-separated list of tools to check and install via Homebrew + required: false + gems: + description: Space-separated list of gems to check and install via gem + required: false + +runs: + using: "composite" + steps: + - name: Install Dependencies + shell: bash + run: | + set -euo pipefail + + if [ -n "${{ inputs.tools }}" ]; then + echo "šŸ” Checking for Homebrew..." + if ! command -v brew >/dev/null; then + echo "āŒ Homebrew is required but not installed. Aborting." + exit 1 + fi + + echo "šŸ”§ Installing missing brew tools..." + for tool in ${{ inputs.tools }}; do + if command -v "$tool" >/dev/null; then + echo "āœ… $tool is already installed." + else + echo "šŸ“¦ Installing $tool via brew..." + brew install "$tool" + fi + done + fi + + if [ -n "${{ inputs.gems }}" ]; then + echo "šŸ”§ Installing missing gems..." + for gem in ${{ inputs.gems }}; do + if gem list -i "$gem" >/dev/null; then + echo "āœ… $gem gem is already installed." + else + echo "šŸ’Ž Installing $gem via gem..." + gem install "$gem" + fi + done + fi + + echo "āœ… All dependencies are ready." diff --git a/.github/actions/package-xcframework/action.yaml b/.github/actions/package-xcframework/action.yaml new file mode 100644 index 0000000..cb6154a --- /dev/null +++ b/.github/actions/package-xcframework/action.yaml @@ -0,0 +1,34 @@ +name: Package XCFramework and LICENSE +description: Zips the built XCFramework and LICENSE into a versioned release artifact + +inputs: + package_name: + description: The name of the package (e.g., MyLibrary-1.0.0) + required: true + xcframework_path: + description: The path to the built .xcframework + required: true + license_path: + description: The path to the LICENSE file + required: true + +outputs: + zip_name: + description: The name of the created zip file + value: ${{ steps.package.outputs.zip_name }} + +runs: + using: "composite" + steps: + - id: package + shell: bash + run: | + set -euo pipefail + ZIP_NAME="${{ inputs.package_name }}.zip" + mkdir -p release + cp -R "${{ inputs.xcframework_path }}" release/ + cp "${{ inputs.license_path }}" release/ + cd release + zip -r "../$ZIP_NAME" . + echo "āœ… Packaged XCFramework and LICENSE into $ZIP_NAME" + echo "zip_name=$ZIP_NAME" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/set-xcode-version/action.yml b/.github/actions/set-xcode-version/action.yml new file mode 100644 index 0000000..8432bca --- /dev/null +++ b/.github/actions/set-xcode-version/action.yml @@ -0,0 +1,18 @@ +name: Set Xcode Version +description: Selects the desired Xcode version using xcode-select. +inputs: + xcode-version: + description: The Xcode version to select (e.g., 16.4) + required: true +runs: + using: 'composite' + steps: + - run: | + set -e + echo "Setting Xcode version to ${{ inputs.xcode-version }}..." + if ! sudo xcode-select -s /Applications/Xcode_${{ inputs.xcode-version }}.app/Contents/Developer; then + echo "āŒ Failed to select Xcode ${{ inputs.xcode-version }}. Listing available Xcodes:" + ls /Applications | grep Xcode + exit 1 + fi + shell: bash diff --git a/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from pull_request_template.md rename to .github/pull_request_template.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c58954d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,180 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write # For PR comments + +env: + PROJECT_NAME: OSBarcodeLib + SCHEME_NAME: OSBarcodeLib + XCODEPROJ_PATH: OSBarcodeLib.xcodeproj + XCODE_VERSION: 16.4 + DESTINATION: 'platform=iOS Simulator,OS=latest,name=iPhone 16' + COVERAGE_TARGET_FILTER: OSBarcodeLib + BUILD_REPORTS_DIR: build/reports + SONAR_REPORTS_DIR: sonar-reports + +jobs: + test: + name: Run Tests + runs-on: macos-15 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + with: + tools: swiftlint xcbeautify + + - name: Set Xcode version + uses: ./.github/actions/set-xcode-version + with: + xcode-version: ${{ env.XCODE_VERSION }} + + - name: Run Unit Tests + id: unit_tests + env: + SCHEME_NAME: ${{ env.SCHEME_NAME }} + XCODEPROJ_PATH: ${{ env.XCODEPROJ_PATH }} + IOS_SIMULATOR_DEVICE: ${{ env.IOS_SIMULATOR_DEVICE }} + DESTINATION: ${{ env.DESTINATION }} + run: | + set -euo pipefail + XCRESULT_NAME="TestResults.xcresult" + mkdir -p "$BUILD_REPORTS_DIR" + xcodebuild test \ + -project "$XCODEPROJ_PATH" \ + -scheme "$SCHEME_NAME" \ + -destination "$DESTINATION" \ + -configuration Debug \ + -enableCodeCoverage YES \ + -resultBundlePath "$XCRESULT_NAME" \ + SKIP_SCRIPT_PHASES=YES \ + CODE_SIGNING_ALLOWED=NO | xcbeautify --report junit --report-path "$BUILD_REPORTS_DIR" + echo "xcresult_name=$XCRESULT_NAME" >> "$GITHUB_OUTPUT" + + - name: Generate Code Coverage Report for SonarQube + continue-on-error: true + env: + XCRESULT_NAME: ${{ steps.unit_tests.outputs.xcresult_name }} + run: | + set -euo pipefail + echo "šŸ” Generating SonarQube coverage report..." + + if [ ! -d "$XCRESULT_NAME" ]; then + echo "āš ļø $XCRESULT_NAME not found. Skipping coverage report generation." + exit 0 + fi + + mkdir -p ${{ env.SONAR_REPORTS_DIR }} + + echo "šŸ“¦ Downloading coverage converter script..." + curl -sSL https://raw.githubusercontent.com/SonarSource/sonar-scanning-examples/master/swift-coverage/swift-coverage-example/xccov-to-sonarqube-generic.sh -o xccov-to-sonarqube-generic.sh + chmod +x xccov-to-sonarqube-generic.sh + + echo "šŸ“ Running coverage converter..." + ./xccov-to-sonarqube-generic.sh TestResults.xcresult > ${{ env.SONAR_REPORTS_DIR }}/sonarqube-generic-coverage.xml + echo "āœ… SonarQube coverage report generated successfully" + + - name: Run SwiftLint for SonarQube + run: | + set -euo pipefail + echo "šŸ” Running SwiftLint..." + mkdir -p ${{ env.SONAR_REPORTS_DIR }} + swiftlint --reporter checkstyle > "${{ env.SONAR_REPORTS_DIR }}/swiftlint.xml" || { + echo "āš ļø SwiftLint finished with issues." + exit 0 + } + echo "āœ… SwiftLint report generated successfully" + + - name: Setup SonarQube Scanner + uses: warchant/setup-sonar-scanner@v8 + + - name: Send to SonarCloud + id: sonarcloud + continue-on-error: true + run: | + set -euo pipefail + if [ -z "${{ secrets.SONAR_TOKEN }}" ]; then + echo "āš ļø SONAR_TOKEN secret is not set. Skipping SonarCloud analysis." + exit 0 + fi + if [ -f "sonar-project.properties" ]; then + echo "šŸ” Sending results to SonarCloud..." + echo "šŸ“¦ Commit: ${{ github.sha }}" + if [ "${{ github.ref_name }}" = "main" ]; then + echo "🌟 Analyzing main branch" + sonar-scanner + else + echo "🌿 Analyzing feature branch: ${{ github.ref_name }}" + sonar-scanner -Dsonar.branch.name="${{ github.ref_name }}" + fi + else + echo "āš ļø sonar-project.properties not found, skipping SonarCloud" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: Upload Test Results + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-results + path: | + ${{ steps.unit_tests.outputs.xcresult_name }} + ${{ env.SONAR_REPORTS_DIR }} + ${{ env.BUILD_REPORTS_DIR }} + + - name: Comment Test Results + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + env: + XCRESULT_NAME: ${{ steps.unit_tests.outputs.xcresult_name }} + COVERAGE_TARGET_FILTER: ${{ env.COVERAGE_TARGET_FILTER }} + with: + script: | + const { execSync } = require('child_process'); + const fs = require('fs'); + + console.log('šŸ“ Starting to comment test results...'); + let coveragePercentage = 'N/A'; + try { + const xcresultName = process.env.XCRESULT_NAME; + const coverageTarget = process.env.COVERAGE_TARGET_FILTER; + console.log(`Checking result file: ${xcresultName}`); + if (fs.existsSync(xcresultName)) { + console.log('Result file found. Calculating coverage...'); + const output = execSync(`xcrun xccov view --report "${xcresultName}"`).toString(); + const match = output.match(new RegExp(`${coverageTarget}.*?([0-9]+\\.[0-9]+%)`)); + if (match && match[1]) { + coveragePercentage = match[1]; + console.log(`Coverage found: ${coveragePercentage}`); + } else { + console.log('Coverage not found in report.'); + } + } else { + console.log('Result file not found.'); + } + } catch (e) { + console.error('Error calculating coverage:', e); + coveragePercentage = 'N/A'; + } + + console.log('Commenting on PR with test results and coverage...'); + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `āœ… **Tests**: All passed\nšŸ“Š **Coverage**: ${coveragePercentage}` + }); + console.log('Comment sent successfully.'); diff --git a/.github/workflows/github_actions.yml b/.github/workflows/github_actions.yml deleted file mode 100644 index 95c71a2..0000000 --- a/.github/workflows/github_actions.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: GitHub Actions - -on: - pull_request: - types: [opened, synchronize, reopened] - -jobs: - test: - name: Unit-Tests - runs-on: macos-14 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Java 17 - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '17' - - - name: Link SwiftLint or install it - run: brew link --overwrite swiftlint || brew install swiftlint - - - name: Set up XCode - run: sudo xcode-select --switch /Applications/Xcode_15.0.app - - - name: Bundle Install - run: bundle install - - - name: Unit tests - run: bundle exec fastlane unit_tests - - - name: Code Coverage - run: bundle exec fastlane coverage - - - name: Lint - run: bundle exec fastlane lint - - - name: Setup sonarqube - uses: warchant/setup-sonar-scanner@v8 - - - name: Send to Sonarcloud - run: bundle exec fastlane sonarqube - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONARCLOUD_KEY }} diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml index 70212ec..fa04da9 100644 --- a/.github/workflows/prepare_release.yml +++ b/.github/workflows/prepare_release.yml @@ -3,79 +3,147 @@ name: Prepare Release on: workflow_dispatch: inputs: - versionBumpLevel: - description: 'Version bump level (patch, minor, major)' - required: true + bump: + description: 'Version bump type (ignored if version is set)' + required: false type: choice - default: 'patch' options: - - patch - - minor - - major + - patch + - minor + - major + version: + description: 'Set specific version (e.g., 1.2.3)' + required: false + +env: + PROJECT_NAME: OSBarcodeLib + PBXPROJ: OSBarcodeLib.xcodeproj/project.pbxproj + XCODE_VERSION: 16.4 + CHANGELOG_PATH: CHANGELOG.md + LICENSE_PATH: LICENSE + PODSPEC_FILE: OSBarcodeLib.podspec jobs: - build-and-release: - if: github.ref == 'refs/heads/main' - runs-on: macos-14 + prepare-release: + name: Prepare Release + runs-on: macos-15 + if: github.ref_name == 'main' + steps: - - name: Checkout + - name: Checkout code uses: actions/checkout@v4 - - - name: Link SwiftLint or install it - run: brew link --overwrite swiftlint || brew install swiftlint - - - name: Set up XCode - run: sudo xcode-select --switch /Applications/Xcode_15.0.app - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3' - - - name: Bump version - run: ruby ./scripts/bump_versions.rb ${{ github.event.inputs.versionBumpLevel }} + fetch-depth: 0 - - name: Build XCFramework - run: ./scripts/build_framework.sh + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + with: + tools: gh - - name: Get new version - id: version - run: echo "VERSION=$(ruby -e 'puts File.read("./OSBarcodeLib.podspec").match(/spec.version.*=.*''(\d+\.\d+\.\d+)''/)[1]')" >> $GITHUB_ENV + - name: Get current project version + id: get_version + uses: ./.github/actions/get-project-version + with: + project_name: ${{ env.PROJECT_NAME }} - - name: Create new branch + - name: Bump project version + id: bump_version + env: + CURRENT_VERSION: ${{ steps.get_version.outputs.version }} + INPUT_BUMP: ${{ github.event.inputs.bump }} + INPUT_VERSION: ${{ github.event.inputs.version }} run: | - git switch --create "prepare-new-release-${{ env.VERSION }}" + set -euo pipefail + echo "ā¬†ļø Bumping project version..." + if [ -n "$INPUT_VERSION" ]; then + if ! [[ "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "āŒ Version must be in format M.m.p (e.g., 1.2.3)" + exit 1 + fi + NEW_VERSION="$INPUT_VERSION" + else + IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" + PATCH="${PATCH:-0}" + case "$INPUT_BUMP" in + major) + MAJOR=$((MAJOR+1)); MINOR=0; PATCH=0;; + minor) + MINOR=$((MINOR+1)); PATCH=0;; + *) + PATCH=$((PATCH+1));; + esac + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + fi + echo "šŸ”¢ New version: $NEW_VERSION" + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT - - name: Move zip file to root and push changes + - name: Update project files + env: + PBXPROJ: ${{ env.PBXPROJ }} + PODSPEC_FILE: ${{ env.PODSPEC_FILE }} + CHANGELOG_PATH: ${{ env.CHANGELOG_PATH }} + NEW_VERSION: ${{ steps.bump_version.outputs.new_version }} run: | - if [ -f OSBarcodeLib.zip ]; then - rm OSBarcodeLib.zip + set -euo pipefail + + echo "šŸ› ļø Updating MARKETING_VERSION..." + sed -i '' -E "s/MARKETING_VERSION = [0-9]+\.[0-9]+(\.[0-9]+)?;/MARKETING_VERSION = $NEW_VERSION;/g" "$PBXPROJ" + echo "šŸ› ļø Updating CURRENT_PROJECT_VERSION..." + current_proj_version=$(grep -m1 'CURRENT_PROJECT_VERSION =' "$PBXPROJ" | sed -E 's/.*CURRENT_PROJECT_VERSION = ([0-9]+);/\1/') + new_proj_version=$((current_proj_version+1)) + sed -i '' -E "s/CURRENT_PROJECT_VERSION = [0-9]+;/CURRENT_PROJECT_VERSION = $new_proj_version;/g" "$PBXPROJ" + echo "āœ… Bumped MARKETING_VERSION to $NEW_VERSION, CURRENT_PROJECT_VERSION to $new_proj_version" + + echo "šŸ› ļø Updating version in $PODSPEC_FILE..." + if [ -f "$PODSPEC_FILE" ]; then + sed -i '' -E "s/^([[:space:]]*[^[:space:]]+\.version[[:space:]]*=[[:space:]]*['\"])[^'\"]+(['\"])/\1$NEW_VERSION\2/" "$PODSPEC_FILE" + echo "āœ… Podspec version updated to $NEW_VERSION" else - echo "File does not exist." + echo "āš ļø Podspec file not found: $PODSPEC_FILE" fi - mv build/OSBarcodeLib.zip . - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - git add . - git commit -m "chore: Bump version to ${{ env.VERSION }}" - git push origin HEAD:prepare-new-release-${{ env.VERSION }} - - name: Create pull request - id: create_pr + echo "šŸ“ Updating $CHANGELOG_PATH..." + TODAY=$(date +%Y-%m-%d) + awk -v ver="$NEW_VERSION" -v today="$TODAY" ' + BEGIN { unreleased_found=0 } + /^## \[Unreleased\]/ { + print $0; print ""; print "## [" ver "] - " today; unreleased_found=1; next + } + { print $0 } + ' "$CHANGELOG_PATH" > "$CHANGELOG_PATH.tmp" && mv "$CHANGELOG_PATH.tmp" "$CHANGELOG_PATH" + echo "āœ… CHANGELOG updated for version $NEW_VERSION" + + - name: Create release branch, commit and push changes + id: create_release_branch + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.bump_version.outputs.new_version }} run: | - gh pr create -B main -H prepare-new-release-${{ env.VERSION }} --title 'Prepare `main` to Release `${{ env.VERSION }}`' --body 'Bumps version to `${{ env.VERSION }}`.
Creates an updated and ready-to-be-released `OSBarcodeLib.zip`.' - PR_NUMBER=$(gh pr view --json number --jq '.number') - echo "PR_NUMBER=${PR_NUMBER}" >> $GITHUB_ENV + set -euo pipefail + BRANCH_NAME="release/v$VERSION" + git config user.name "github-actions[bot] (on behalf of ${{ github.actor }})" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH_NAME" + git add . + git commit -m "chore(release): prepare release v$VERSION" + git push origin "$BRANCH_NAME" + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Ensure 'release' label exists env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh label create release --color FFD700 --description "Release PRs" || true - - name: Add label to the pull request - run: | - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ github.repository }}/issues/${{ env.PR_NUMBER }}/labels \ - -f "labels[]=release" + - name: Create Pull Request env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.bump_version.outputs.new_version }} + BRANCH_NAME: ${{ steps.create_release_branch.outputs.branch_name }} + run: | + set -euo pipefail + gh pr create \ + --title "Release v$VERSION" \ + --body "Automated PR to release v$VERSION." \ + --head $BRANCH_NAME \ + --base main \ + --label release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..84641d1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,145 @@ +name: Release + +on: + pull_request: + types: [closed] + branches: + - 'main' + +env: + PROJECT_NAME: OSBarcodeLib + XCODE_VERSION: 16.4 + CHANGELOG_PATH: CHANGELOG.md + LICENSE_PATH: LICENSE + PODSPEC_FILE: OSBarcodeLib.podspec + +jobs: + tag_and_release: + name: Release and Publish + runs-on: macos-15 + if: >- + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'release') + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + with: + tools: gh + gems: cocoapods + + - name: Get current project version + id: get_version + uses: ./.github/actions/get-project-version + with: + project_name: ${{ env.PROJECT_NAME }} + + - name: Get release notes for this version + id: release_notes + env: + VERSION: ${{ steps.get_version.outputs.version }} + CHANGELOG_PATH: ${{ env.CHANGELOG_PATH }} + run: | + set -euo pipefail + if [ ! -f "$CHANGELOG_PATH" ]; then + echo "āŒ Changelog file not found: $CHANGELOG_PATH" + exit 1 + fi + echo "šŸ“œ Extracting release notes for version $VERSION..." + release_notes_section=$(awk "/^## \[${VERSION}\]/ {flag=1; next} flag && /^## \\[/ {exit} flag {print}" "$CHANGELOG_PATH" | sed '/^\s*$/d') + if [ -n "$release_notes_section" ]; then + echo "$release_notes_section" + echo 'release_notes<> $GITHUB_OUTPUT + echo "$release_notes_section" >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + else + echo "āš ļø No release notes found for version $VERSION." + exit 0 + fi + + - name: Set Xcode version + uses: ./.github/actions/set-xcode-version + with: + xcode-version: ${{ env.XCODE_VERSION }} + + - name: Build XCFramework + id: build_xcframework + uses: ./.github/actions/build-xcframework + with: + project_name: ${{ env.PROJECT_NAME }} + + - name: Package XCFramework + uses: ./.github/actions/package-xcframework + id: package + with: + package_name: ${{ env.PROJECT_NAME }} + xcframework_path: ${{ steps.build_xcframework.outputs.xcframework_path }} + license_path: ${{ env.LICENSE_PATH }} + + - name: Create tag + id: create_tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.get_version.outputs.version }} + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag v$VERSION -m "Release version $VERSION" + git push origin v$VERSION + echo "Tag v$VERSION created." + echo "tag=v$VERSION" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TITLE: ${{ steps.create_tag.outputs.tag }} + RELEASE_NOTES: ${{ steps.release_notes.outputs.release_notes }} + ASSET_PATH: ${{ steps.package.outputs.zip_name }} + run: | + set -euo pipefail + gh release create $TITLE \ + --title "$TITLE" \ + --notes "$RELEASE_NOTES" \ + "$ASSET_PATH" + + - name: Publish Pod + if: hashFiles('${{ env.PODSPEC_FILE }}') != '' + env: + COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} + run: | + set -euo pipefail + if [ -z "${COCOAPODS_TRUNK_TOKEN:-}" ]; then + echo "āŒ COCOAPODS_TRUNK_TOKEN secret is not set. Please set it in your repository secrets." + exit 1 + fi + echo "šŸš€ Deploying podspec to CocoaPods..." + pod trunk push "$PODSPEC_FILE" --allow-warnings + + - name: Delete source branch + if: github.event.pull_request.head.ref != 'main' + run: | + set +e + git push origin --delete ${{ github.event.pull_request.head.ref }} + set -e + + delete_branch_if_pr_closed_without_merge: + name: Delete Source Branch If PR Closed Without Merge + runs-on: macos-15 + if: >- + github.event.pull_request.merged == false && + github.event.pull_request.head.ref != 'main' && + contains(github.event.pull_request.labels.*.name, 'release') + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Delete source branch + run: | + set +e + git push origin --delete ${{ github.event.pull_request.head.ref }} + set -e diff --git a/.github/workflows/release_and_publish.yml b/.github/workflows/release_and_publish.yml deleted file mode 100644 index 92cc14a..0000000 --- a/.github/workflows/release_and_publish.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Release and Publish - -on: - pull_request: - types: [closed] - branches: - - 'main' - -jobs: - post-merge: - if: contains(github.event.pull_request.labels.*.name, 'release') && github.event.pull_request.merged == true - runs-on: macos-14 - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Set up Cocoapods - run: gem install cocoapods - - - name: Get new version - id: version - run: echo "VERSION=$(ruby -e 'puts File.read("./OSBarcodeLib.podspec").match(/spec.version.*=.*''(\d+\.\d+\.\d+)''/)[1]')" >> $GITHUB_ENV - - - name: Extract release notes - run: sh scripts/extract_release_notes.sh "${{ env.VERSION }}" >> release_notes.md - - - name: Create Tag - id: create_tag - run: | - # Define the tag name and message - TAG_NAME="${{ env.VERSION }}" - TAG_MESSAGE="Tag for version ${{ env.VERSION }}" - - # Create the tag - git tag -a "$TAG_NAME" -m "$TAG_MESSAGE" - git push origin "$TAG_NAME" - - echo "Tag created: $TAG_NAME" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Release - run: | - # Extract the tag name - TAG_NAME="${{ env.VERSION }}" - RELEASE_NOTES="$(cat release_notes.md)" - - # Create the release using GitHub CLI - gh release create "$TAG_NAME" \ - --title "$TAG_NAME" \ - --notes "$RELEASE_NOTES" \ - "OSBarcodeLib.zip" - - echo "Release created for tag: $TAG_NAME" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Deploy to Cocoapods - run: pod trunk push ./OSBarcodeLib.podspec --allow-warnings - env: - COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} - - - name: Delete Release Branch - run: git push origin --delete prepare-new-release-${{ env.VERSION }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Gemfile b/Gemfile deleted file mode 100644 index a80b326..0000000 --- a/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -gem "fastlane" -gem "slather" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index f8ead4f..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,267 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.7) - base64 - nkf - rexml - activesupport (7.2.0) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - artifactory (3.0.17) - atomos (0.1.3) - aws-eventstream (1.3.0) - aws-partitions (1.963.0) - aws-sdk-core (3.201.4) - aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) - jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.88.0) - aws-sdk-core (~> 3, >= 3.201.0) - aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.157.0) - aws-sdk-core (~> 3, >= 3.201.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.5) - aws-sigv4 (1.9.1) - aws-eventstream (~> 1, >= 1.0.2) - babosa (1.0.4) - base64 (0.2.0) - bigdecimal (3.1.8) - claide (1.1.0) - clamp (1.3.2) - colored (1.2) - colored2 (3.1.2) - commander (4.6.0) - highline (~> 2.0.0) - concurrent-ruby (1.3.4) - connection_pool (2.4.1) - declarative (0.0.20) - digest-crc (0.6.5) - rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20240107) - dotenv (2.8.1) - drb (2.2.1) - emoji_regex (3.2.3) - excon (0.111.0) - faraday (1.10.3) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) - ruby2_keywords (>= 0.0.4) - faraday-cookie_jar (0.0.7) - faraday (>= 0.8.0) - http-cookie (~> 1.0.0) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.2) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - faraday_middleware (1.2.0) - faraday (~> 1.0) - fastimage (2.3.1) - fastlane (2.222.0) - CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.8, < 3.0.0) - artifactory (~> 3.0) - aws-sdk-s3 (~> 1.0) - babosa (>= 1.0.3, < 2.0.0) - bundler (>= 1.12.0, < 3.0.0) - colored (~> 1.2) - commander (~> 4.6) - 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) - 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) - mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (>= 2.0.0, < 3.0.0) - naturally (~> 2.2) - optparse (>= 0.1.1, < 1.0.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.3.0) - xcpretty-travis-formatter (>= 0.0.3, < 2.0.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.7.1) - 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.4.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.6) - domain_name (~> 0.5) - httpclient (2.8.3) - i18n (1.14.5) - concurrent-ruby (~> 1.0) - jmespath (1.6.2) - json (2.7.2) - jwt (2.8.2) - base64 - logger (1.6.0) - mini_magick (4.13.2) - mini_mime (1.1.5) - minitest (5.24.1) - multi_json (1.15.0) - multipart-post (2.4.1) - nanaimo (0.3.0) - naturally (2.2.1) - nkf (0.2.0) - nokogiri (1.16.7-aarch64-linux) - racc (~> 1.4) - nokogiri (1.16.7-arm-linux) - racc (~> 1.4) - nokogiri (1.16.7-arm64-darwin) - racc (~> 1.4) - nokogiri (1.16.7-x86-linux) - racc (~> 1.4) - nokogiri (1.16.7-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) - racc (~> 1.4) - optparse (0.5.0) - os (1.1.4) - plist (3.7.1) - public_suffix (6.0.1) - racc (1.8.1) - rake (13.2.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.3.5) - strscan - rouge (2.0.7) - ruby2_keywords (0.0.5) - rubyzip (2.3.2) - securerandom (0.3.1) - security (0.1.5) - signet (0.19.0) - addressable (~> 2.8) - faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) - multi_json (~> 1.10) - simctl (1.6.10) - CFPropertyList - naturally - slather (2.8.3) - CFPropertyList (>= 2.2, < 4) - activesupport - clamp (~> 1.3) - nokogiri (>= 1.14.3) - xcodeproj (~> 1.21) - strscan (3.1.0) - 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) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - uber (0.1.0) - unicode-display_width (2.5.0) - word_wrap (1.0.0) - xcodeproj (1.25.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (>= 3.3.2, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.1) - xcpretty (~> 0.2, >= 0.0.7) - -PLATFORMS - aarch64-linux - arm-linux - arm64-darwin - x86-linux - x86_64-darwin - x86_64-linux - -DEPENDENCIES - fastlane - slather - -BUNDLED WITH - 2.5.10 diff --git a/OSBarcodeLib.zip b/OSBarcodeLib.zip deleted file mode 100644 index 6e4b5c7..0000000 Binary files a/OSBarcodeLib.zip and /dev/null differ diff --git a/fastlane/Appfile b/fastlane/Appfile deleted file mode 100644 index 1803063..0000000 --- a/fastlane/Appfile +++ /dev/null @@ -1,6 +0,0 @@ -# app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app -# apple_id("[[APPLE_ID]]") # Your Apple email address - - -# For more information about the Appfile, see: -# https://docs.fastlane.tools/advanced/#appfile diff --git a/fastlane/Fastfile b/fastlane/Fastfile deleted file mode 100644 index 686d228..0000000 --- a/fastlane/Fastfile +++ /dev/null @@ -1,44 +0,0 @@ -# This file contains the fastlane.tools configuration -# You can find the documentation at https://docs.fastlane.tools -# -# For a list of all available actions, check out -# -# https://docs.fastlane.tools/actions -# -# For a list of all available plugins, check out -# -# https://docs.fastlane.tools/plugins/available-plugins -# - -# Uncomment the line if you want fastlane to automatically update itself -# update_fastlane - -default_platform(:ios) - -platform :ios do - desc "Lane to run the unit tests" - lane :unit_tests do - run_tests(scheme: "OSBarcodeLib") - end - - desc "Code coverage" - lane :coverage do - slather( - scheme: "OSBarcodeLib", - proj: "OSBarcodeLib.xcodeproj", - output_directory: "sonar-reports", - sonarqube_xml: "true" - ) - end - - lane :lint do - swiftlint( - output_file: "sonar-reports/OSBarcodeLib-swiftlint.txt", - ignore_exit_status: true - ) - end - - lane :sonarqube do - sonar - end -end diff --git a/fastlane/README.md b/fastlane/README.md deleted file mode 100644 index bd01748..0000000 --- a/fastlane/README.md +++ /dev/null @@ -1,32 +0,0 @@ -fastlane documentation ----- - -# Installation - -Make sure you have the latest version of the Xcode command line tools installed: - -```sh -xcode-select --install -``` - -For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) - -# Available Actions - -## iOS - -### ios unit_tests - -```sh -[bundle exec] fastlane ios unit_tests -``` - -Lane to run the unit tests - ----- - -This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. - -More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). - -The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).