├── .Package.template.swift ├── .github └── workflows │ ├── create-releases.yml │ ├── delete-releases.yml │ ├── fetch-releases.yml │ └── test.yml ├── .gitignore ├── Docs └── Images │ ├── NMapsMap-SwiftPM-Icon.svg │ └── NMapsMap-SwiftPM-Logotype.svg ├── Package.swift └── README.md /.Package.template.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "NMapsMap", 7 | platforms: [ 8 | .iOS(.v9) 9 | ], 10 | products: [ 11 | .library( 12 | name: "NMapsMap", 13 | targets: ["NMapsMap"] 14 | ) 15 | ], 16 | targets: [ 17 | .binaryTarget( 18 | name: "NMapsMap", 19 | url: "<#url#>", 20 | checksum: "<#checksum#>" 21 | ) 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /.github/workflows/create-releases.yml: -------------------------------------------------------------------------------- 1 | name: Create releases 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tags: 7 | description: 'Tags (JSON)' 8 | required: true 9 | default: '[{ src: "release/1.0.0", dest: "v1.0.0" }]' 10 | 11 | env: 12 | upstream_repo_full_name: 'navermaps/NMapsMap' 13 | git_config_user_name: 'github-actions' 14 | git_config_user_email: '41898282+github-actions[bot]@users.noreply.github.com' 15 | 16 | # TODO: Assertion 추가하기 17 | jobs: 18 | create-release: 19 | name: Create a release ${{ matrix.tag.dest }} 20 | strategy: 21 | max-parallel: 1 22 | fail-fast: true 23 | matrix: 24 | tag: ${{ fromJson(github.event.inputs.tags) }} 25 | if: ${{ github.event.inputs.tags != null }} 26 | runs-on: macos-latest 27 | steps: 28 | - name: Checkout ${{ github.repository }} 29 | uses: actions/checkout@v2 30 | with: 31 | ref: ${{ github.ref }} 32 | path: working_repo 33 | 34 | - name: Checkout ${{ env.upstream_repo_full_name }} ${{ matrix.tag.src }} 35 | uses: actions/checkout@v2 36 | with: 37 | repository: ${{ env.upstream_repo_full_name }} 38 | ref: ${{ matrix.tag.src }} 39 | path: upstream_repo 40 | lfs: true 41 | 42 | - name: Check architecture types in the binary 43 | run: xcrun lipo upstream_repo/framework/NMapsMap.framework/NMapsMap -archs 44 | 45 | - name: Create a thin binary for iphoneos 46 | run: | 47 | mkdir -p binaries/iphoneos 48 | cp -a upstream_repo/framework/NMapsMap.framework binaries/iphoneos/NMapsMap.framework 49 | xcrun lipo binaries/iphoneos/NMapsMap.framework/NMapsMap \ 50 | -output binaries/iphoneos/NMapsMap.framework/NMapsMap \ 51 | -extract arm64 \ 52 | -extract armv7 53 | 54 | - name: Create a thin binary for iphonesimulator 55 | run: | 56 | mkdir -p binaries/iphonesimulator 57 | cp -a upstream_repo/framework/NMapsMap.framework binaries/iphonesimulator/NMapsMap.framework 58 | xcrun lipo binaries/iphonesimulator/NMapsMap.framework/NMapsMap \ 59 | -output binaries/iphonesimulator/NMapsMap.framework/NMapsMap \ 60 | -extract i386 \ 61 | -extract x86_64 62 | 63 | - name: Create an XCFramework 64 | working-directory: binaries 65 | run: | 66 | xcodebuild -create-xcframework \ 67 | -framework iphoneos/NMapsMap.framework \ 68 | -framework iphonesimulator/NMapsMap.framework \ 69 | -output NMapsMap.xcframework 70 | 71 | - name: Create a ZIP archive 72 | working-directory: binaries 73 | run: zip -r -X NMapsMap.xcframework.zip NMapsMap.xcframework 74 | 75 | - name: Estimate an asset URL 76 | run: | 77 | url=https://github.com/${{ github.repository }}/releases/download/${{ matrix.tag.dest }}/NMapsMap.xcframework.zip 78 | echo "url=$url" >> $GITHUB_ENV 79 | echo $url 80 | 81 | - name: Compute a checksum from the ZIP archive 82 | working-directory: working_repo 83 | run: | 84 | touch Package.swift 85 | checksum=$(swift package compute-checksum ../binaries/NMapsMap.xcframework.zip) 86 | echo "checksum=$checksum" >> $GITHUB_ENV 87 | echo $checksum 88 | 89 | - name: Generate Package.swift with URL and checksum 90 | working-directory: working_repo 91 | run: | 92 | sed -e "s|<#url#>|${{ env.url }}|g" -e "s|<#checksum#>|${{ env.checksum }}|g" .Package.template.swift > Package.swift 93 | cat Package.swift 94 | 95 | - name: Setup Git configurations 96 | working-directory: working_repo 97 | run: | 98 | git config user.name "${{ env.git_config_user_name }}" 99 | git config user.email "${{ env.git_config_user_email }}" 100 | 101 | - name: Show remotes in repository 102 | working-directory: working_repo 103 | run: git remote 104 | 105 | - name: Add, commit and push to ${{ github.repository }} 106 | working-directory: working_repo 107 | # 태그를 미리 지정하지 않으면 create-release 액션이 이전 커밋에 태그를 지정하고 릴리즈하는 문제가 발생한다. 108 | run: | 109 | git add -A 110 | git commit -m "Bump to ${{ matrix.tag.dest }}" 111 | git tag ${{ matrix.tag.dest }} 112 | git pull --rebase 113 | git push origin HEAD 114 | git push --tags origin HEAD 115 | 116 | - name: Create a release 117 | id: create_release 118 | uses: actions/create-release@v1 119 | env: 120 | GITHUB_TOKEN: ${{ github.token }} 121 | with: 122 | tag_name: ${{ matrix.tag.dest }} 123 | 124 | - name: Upload a release asset 125 | id: upload_release_asset 126 | uses: actions/upload-release-asset@v1 127 | env: 128 | GITHUB_TOKEN: ${{ github.token }} 129 | with: 130 | upload_url: ${{ steps.create_release.outputs.upload_url }} 131 | asset_path: binaries/NMapsMap.xcframework.zip 132 | asset_name: NMapsMap.xcframework.zip 133 | asset_content_type: application/zip 134 | 135 | - name: Check asset URLs 136 | run: | 137 | echo "${{ env.url }}" 138 | echo "${{ steps.upload_release_asset.outputs.browser_download_url }}" 139 | 140 | - name: List all files in working directory 141 | run: find . 142 | -------------------------------------------------------------------------------- /.github/workflows/delete-releases.yml: -------------------------------------------------------------------------------- 1 | name: Delete releases 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tags: 7 | description: 'Tags (JSON)' 8 | required: true 9 | default: '["release/1.0.0"]' 10 | 11 | jobs: 12 | delete_releases: 13 | name: Delete releases 14 | runs-on: macos-latest 15 | steps: 16 | - name: List releases 17 | id: list_releases 18 | uses: actions/github-script@v3 19 | with: 20 | github-token: ${{ github.token }} 21 | script: | 22 | const passedTags = JSON.parse(context.payload.inputs.tags); 23 | const allReleases = (await github.repos.listReleases({ 24 | owner: context.repo.owner, 25 | repo: context.repo.repo, 26 | })).data; 27 | const releasesToDelete = passedTags.includes("**") ? allReleases : allReleases.filter(release => passedTags.includes(release.tag_name)); 28 | core.setOutput("releasesToDelete", releasesToDelete); 29 | console.log("releasesToDelete: ", releasesToDelete); 30 | 31 | - name: Delete releases 32 | if: ${{ steps.list_releases.outputs.releasesToDelete != '[]' }} 33 | uses: actions/github-script@v3 34 | with: 35 | github-token: ${{ github.token }} 36 | script: | 37 | const releasesToDelete = ${{ steps.list_releases.outputs.releasesToDelete }}; 38 | const deletingPromises = releasesToDelete.map((release) => { 39 | return github.repos.deleteRelease({ 40 | owner: context.repo.owner, 41 | repo: context.repo.repo, 42 | release_id: release.id 43 | }); 44 | }); 45 | const deletingResponses = await Promise.all(deletingPromises); 46 | const result = deletingResponses.map((response) => ({ status: response.status, url: response.url })); 47 | console.log(result); 48 | 49 | delete_tags: 50 | name: Delete tags 51 | needs: delete_releases 52 | runs-on: macos-latest 53 | steps: 54 | - name: List tags 55 | id: list_tags 56 | uses: actions/github-script@v3 57 | with: 58 | github-token: ${{ github.token }} 59 | script: | 60 | const passedTags = JSON.parse(context.payload.inputs.tags); 61 | const allTags = (await github.repos.listTags({ 62 | owner: context.repo.owner, 63 | repo: context.repo.repo, 64 | })).data; 65 | const tagsToDelete = passedTags.includes("**") ? allTags : allTags.filter(tag => passedTags.includes(tag.name)); 66 | core.setOutput("tagsToDelete", tagsToDelete); 67 | console.log("tagsToDelete: ", tagsToDelete); 68 | 69 | - name: Delete tags 70 | if: ${{ steps.list_tags.outputs.tagsToDelete != '[]' }} 71 | uses: actions/github-script@v3 72 | with: 73 | github-token: ${{ github.token }} 74 | script: | 75 | const tagsToDelete = ${{ steps.list_tags.outputs.tagsToDelete }}; 76 | const deletingPromises = tagsToDelete.map((tag) => { 77 | return github.git.deleteRef({ 78 | owner: context.repo.owner, 79 | repo: context.repo.repo, 80 | ref: `tags/${tag.name}` 81 | }); 82 | }); 83 | const deletingResponses = await Promise.all(deletingPromises); 84 | const result = deletingResponses.map((response) => ({ status: response.status, url: response.url })); 85 | console.log(result); -------------------------------------------------------------------------------- /.github/workflows/fetch-releases.yml: -------------------------------------------------------------------------------- 1 | name: Fetch releases 2 | 3 | on: 4 | # schedule: 5 | # - cron: '0 * * * *' 6 | workflow_dispatch: 7 | 8 | env: 9 | upstream_repo_owner: 'navermaps' 10 | upstream_repo_name: 'NMapsMap' 11 | function_semver: | 12 | function(tag) { 13 | try { 14 | const regExp = /\d*\.\d*\.\d*.*/; 15 | const prefix = "v"; 16 | return prefix + regExp.exec(tag)[0]; 17 | } catch { 18 | return tag; 19 | } 20 | } 21 | 22 | jobs: 23 | check_pat: 24 | name: Check secrets.PERSONAL_ACCESS_TOKEN 25 | runs-on: macos-latest 26 | steps: 27 | - name: Check if secrets.PERSONAL_ACCESS_TOKEN exists 28 | uses: actions/github-script@v3 29 | with: 30 | script: | 31 | const patIsNotNull = ${{ secrets.PERSONAL_ACCESS_TOKEN != null }}; 32 | if (patIsNotNull) { 33 | console.log("secrets.PERSONAL_ACCESS_TOKEN exists.") 34 | } else { 35 | // TODO: 오류 메시지에 해결 방법 제공하기 36 | core.setFailed( 37 | `secret.PERSONAL_ACCESS_TOKEN doesn't exist. 38 | https://github.com/${context.repo.owner}/${context.repo.repo}/settings/secrets/actions/new` 39 | ); 40 | } 41 | 42 | fetch_releases: 43 | name: Fetch releases 44 | needs: check_pat 45 | runs-on: macos-latest 46 | outputs: 47 | removedTags: ${{ steps.diff_tags.outputs.removedTags }} 48 | addedTags: ${{ steps.diff_tags.outputs.addedTags }} 49 | steps: 50 | - name: List tags on ${{ github.repository }} 51 | id: list_tags_working 52 | uses: actions/github-script@v3 53 | with: 54 | github-token: ${{ github.token }} 55 | script: | 56 | const workingRepoTags = (await github.repos.listTags({ 57 | owner: context.repo.owner, 58 | repo: context.repo.repo 59 | })).data.reverse().map(tag => tag.name); 60 | core.setOutput("workingRepoTags", workingRepoTags); 61 | console.log("workingRepoTags: ", workingRepoTags); 62 | 63 | - name: List tags on ${{ env.upstream_repo_owner }}/${{ env.upstream_repo_name }} 64 | id: list_tags_upstream 65 | uses: actions/github-script@v3 66 | with: 67 | github-token: ${{ github.token }} 68 | script: | 69 | const upstreamRepoTags = (await github.repos.listTags({ 70 | owner: '${{ env.upstream_repo_owner }}', 71 | repo: '${{ env.upstream_repo_name }}' 72 | })).data.reverse().map(tag => tag.name); 73 | core.setOutput("upstreamRepoTags", upstreamRepoTags); 74 | console.log("upstreamRepoTags: ", upstreamRepoTags); 75 | 76 | - name: Diff tags between ${{ github.repository }} and ${{ env.upstream_repo_owner }}/${{ env.upstream_repo_name }} 77 | id: diff_tags 78 | uses: actions/github-script@v3 79 | with: 80 | script: | 81 | const semver = ${{ env.function_semver }}; 82 | const workingRepoTags = ${{ steps.list_tags_working.outputs.workingRepoTags }}; 83 | const upstreamRepoTags = ${{ steps.list_tags_upstream.outputs.upstreamRepoTags }}; 84 | const removedTags = workingRepoTags.filter(tag => !upstreamRepoTags.map(semver).includes(tag)); 85 | const addedTags = upstreamRepoTags.filter(tag => !workingRepoTags.includes(semver(tag))).map(tag => ({ src: tag, dest: semver(tag) })); 86 | core.setOutput("removedTags", removedTags); 87 | core.setOutput("addedTags", addedTags); 88 | console.log("removedTags: ", removedTags); 89 | console.log("addedTags: ", addedTags); 90 | 91 | trigger_workflow: 92 | name: Trigger ${{ matrix.workflow.id }} 93 | strategy: 94 | max-parallel: 1 95 | matrix: 96 | workflow: 97 | - id: 'delete-releases.yml' 98 | tags: ${{ needs.fetch_releases.outputs.removedTags }} 99 | - id: 'create-releases.yml' 100 | tags: ${{ needs.fetch_releases.outputs.addedTags }} 101 | needs: fetch_releases 102 | # if: ${{ matrix.workflow.tags != '[]' }} 103 | runs-on: macos-latest 104 | steps: 105 | - name: Create a workflow dispatch event with ${{ matrix.workflow.tags }} 106 | if: ${{ matrix.workflow.tags != '[]' }} 107 | uses: actions/github-script@v3 108 | with: 109 | github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 110 | script: | 111 | const response = await github.request("POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches", { 112 | owner: context.repo.owner, 113 | repo: context.repo.repo, 114 | ref: context.ref, 115 | workflow_id: '${{ matrix.workflow.id }}', 116 | inputs: { 117 | tags: '${{ matrix.workflow.tags }}' 118 | } 119 | }); 120 | const result = { status: response.status, url: response.url }; 121 | console.log(result); 122 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | test1: 8 | if: true 9 | runs-on: macos-latest 10 | steps: 11 | - name: Set output 12 | id: set_output 13 | uses: actions/github-script@v3 14 | with: 15 | script: | 16 | const sv = require("semver"); 17 | console.log(sv); 18 | 19 | test2: 20 | if: false 21 | runs-on: macos-latest 22 | steps: 23 | - name: Set output 24 | id: set_output 25 | uses: actions/github-script@v3 26 | with: 27 | script: | 28 | core.setOutput("foo", "bar"); 29 | return "baz"; 30 | - name: Get input 31 | id: get_input 32 | uses: actions/github-script@v3 33 | with: 34 | script: | 35 | console.log(`${{ steps.set_output.outputs.foo }}`); 36 | console.log(core.getInput("foo")); 37 | console.log(core.getInput("set_output")); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | # Thumbnails 10 | ._* 11 | 12 | # Files that might appear in the root of a volume 13 | .DocumentRevisions-V100 14 | .fseventsd 15 | .Spotlight-V100 16 | .TemporaryItems 17 | .Trashes 18 | .VolumeIcon.icns 19 | .com.apple.timemachine.donotpresent 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk -------------------------------------------------------------------------------- /Docs/Images/NMapsMap-SwiftPM-Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Docs/Images/NMapsMap-SwiftPM-Logotype.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "NMapsMap", 7 | platforms: [ 8 | .iOS(.v9) 9 | ], 10 | products: [ 11 | .library( 12 | name: "NMapsMap", 13 | targets: ["NMapsMap"] 14 | ) 15 | ], 16 | targets: [ 17 | .binaryTarget( 18 | name: "NMapsMap", 19 | url: "https://github.com/stleamist/NMapsMap-SwiftPM/releases/download/v3.11.0/NMapsMap.xcframework.zip", 20 | checksum: "b6cf0c9468ba3dc7120e545f05fb9c13f64d5ad1b61ebd2268732ae47e45fb20" 21 | ) 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |