diff --git a/.github/workflows/darft_release.yml b/.github/workflows/darft_release.yml new file mode 100644 index 0000000..7431c66 --- /dev/null +++ b/.github/workflows/darft_release.yml @@ -0,0 +1,159 @@ +name: release + +on: + workflow_dispatch: + +env: + go_version: '1.16' + flutter_channel: 'stable' + flutter_version: '2.10.3' + GH_TOKEN: ${{ secrets.GH_TOKEN }} + +jobs: + + ci-pass: + name: CI is green + runs-on: ubuntu-latest + needs: + - check_release + - build_release_assets + steps: + - run: exit 0 + + check_release: + name: Check release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + repository: ${{ github.event.inputs.repo }} + ref: 'master' + - name: Checkout submodules + run: git submodule update --init --recursive + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.go_version }} + - name: Check release + run: | + cd ci + go run ./cmd/check_release + + build_release_assets: + needs: + - check_release + name: Build release assets + strategy: + matrix: + config: + - target: linux + host: ubuntu-latest + - target: windows + host: windows-latest + - target: macos + host: macos-latest + - target: ios + host: macos-latest + - target: android-32 + host: ubuntu-latest + - target: android-arm64 + host: ubuntu-latest + - target: android-x86_64 + host: ubuntu-latest + runs-on: ${{ matrix.config.host }} + + env: + TARGET: ${{ matrix.config.target }} + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup golang + uses: actions/setup-go@v2 + with: + go-version: ${{ env.go_version }} + + - id: check_asset + name: Check asset + run: | + cd ci + go run ./cmd/check_asset + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" + name: Cache Go modules + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" + name: Cache Flutter dependencies + uses: actions/cache@v3 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-cache-${{ env.flutter_version }}-${{ env.flutter_channel }}-${{ hashFiles('**/pubspec.lock') }} + restore-keys: | + ${{ runner.OS }}-flutter-cache-${{ env.flutter_version }}-${{ env.flutter_channel }} + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" + uses: subosito/flutter-action@v2.3.0 + with: + channel: ${{ env.flutter_channel }} + flutter-version: ${{ env.flutter_version }} + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" + name: Cache pub dependencies + uses: actions/cache@v3 + with: + path: ${{ env.PUB_CACHE }} + key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }} + restore-keys: ${{ runner.os }}-pub- + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "android-arm32" | ${{ env.TARGET }} == "android-arm64" | ${{ env.TARGET }} == "android-x86_64" ) + name: Setup java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 8 + cache: 'gradle' + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "android-arm32" | ${{ env.TARGET }} == "android-arm64" | ${{ env.TARGET }} == "android-x86_64" ) + name: Setup android tools + uses: maxim-lobanov/setup-android-tools@v1 + with: + packages: | + platform-tools + platforms;android-32 + build-tools;33.0.0 + ndk;22.1.7171670 + cache: true + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "windows" ) + name: Setup msys2 + uses: msys2/setup-msys2@v2 + with: + install: gcc make + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "windows" ) + name: Setup msys2 + uses: msys2/setup-msys2@v2 + with: + install: gcc make + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "windows" ) + name: Install zip + uses: montudor/action-zip@v1 + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "linux" ) + name: Install appimage + uses: AppImageCrafters/build-appimage@master + + - if: ${{steps.check_asset.outputs.*}} == "BUILD" && ( ${{ env.TARGET }} == "linux" | ${{ env.TARGET }} == "windows" ${{ env.TARGET }} == "macos" ) + name: Install appimage + run: | + go install github.com/go-flutter-desktop/hover@latest + diff --git a/.gitignore b/.gitignore index 986ab8f..68f0aa2 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,8 @@ app.*.map.json ios/build/ +# IDE +*.iml + # APP /lib/assets/version.txt diff --git a/ci/cmd/check_asset/main.go b/ci/cmd/check_asset/main.go new file mode 100644 index 0000000..5dd265f --- /dev/null +++ b/ci/cmd/check_asset/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "ci/commons" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "strings" +) + +const owner = "niuhuan" +const repo = "pikapika" +const ua = "niuhuan pikapika ci" + +func main() { + // get ghToken + ghToken := os.Getenv("GH_TOKEN") + if ghToken == "" { + println("Env ${GH_TOKEN} is not set") + os.Exit(1) + } + // get version + var version commons.Version + codeFile, err := ioutil.ReadFile("version.code.txt") + if err != nil { + panic(err) + } + version.Code = strings.TrimSpace(string(codeFile)) + infoFile, err := ioutil.ReadFile("version.info.txt") + if err != nil { + panic(err) + } + version.Info = strings.TrimSpace(string(infoFile)) + // get target + target := os.Getenv("TARGET") + if ghToken == "" { + println("Env ${TARGET} is not set") + os.Exit(1) + } + // + var releaseFileName string + switch target { + case "macos": + releaseFileName = fmt.Sprintf("pikapika-v1.4.1-android-arm32.apk") + case "ios": + releaseFileName = fmt.Sprintf("pikapika-%v-ios-nosign.ipa", version.Code) + case "windows": + releaseFileName = fmt.Sprintf("pikapika-%v-windows-x86_64.zip", version.Code) + case "linux": + releaseFileName = fmt.Sprintf("pikapika-%v-linux-x86_64.AppImage", version.Code) + case "android-arm32": + releaseFileName = fmt.Sprintf("pikapika-%v-android-arm32.apk", version.Code) + case "android-arm64": + releaseFileName = fmt.Sprintf("pikapika-%v-android-arm64.apk", version.Code) + case "android-x86_64": + releaseFileName = fmt.Sprintf("pikapika-%v-android-x86_64.apk", version.Code) + } + // get version + getReleaseRequest, err := http.NewRequest( + "GET", + fmt.Sprintf("https://api.github.com/repos/%v/%v/releases/tags/%v", owner, repo, version.Code), + nil, + ) + if err != nil { + panic(nil) + } + getReleaseRequest.Header.Set("User-Agent", ua) + getReleaseRequest.Header.Set("Authorization", ghToken) + getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest) + if err != nil { + panic(nil) + } + defer getReleaseResponse.Body.Close() + if getReleaseResponse.StatusCode == 404 { + panic("NOT FOUND RELEASE") + } + buff, err := ioutil.ReadAll(getReleaseResponse.Body) + if err != nil { + panic(nil) + } + var release commons.Release + err = json.Unmarshal(buff, &releaseFileName) + if err != nil { + panic(nil) + } + for _, asset := range release.Assets { + if asset.Name == releaseFileName { + print("EXISTS") + os.Exit(0) + } + } + print("BUILD") +} diff --git a/ci/cmd/check_release/main.go b/ci/cmd/check_release/main.go new file mode 100644 index 0000000..8b737c2 --- /dev/null +++ b/ci/cmd/check_release/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "bytes" + "ci/commons" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "strings" +) + +const owner = "niuhuan" +const repo = "pikapika" +const ua = "niuhuan pikapika ci" +const mainBranch = "master" + +func main() { + // get ghToken + ghToken := os.Getenv("GH_TOKEN") + if ghToken == "" { + println("Env ${GH_TOKEN} is not set") + os.Exit(1) + } + // get version + var version commons.Version + codeFile, err := ioutil.ReadFile("version.code.txt") + if err != nil { + panic(err) + } + version.Code = strings.TrimSpace(string(codeFile)) + infoFile, err := ioutil.ReadFile("version.info.txt") + if err != nil { + panic(err) + } + version.Info = strings.TrimSpace(string(infoFile)) + // get version + getReleaseRequest, err := http.NewRequest( + "GET", + fmt.Sprintf("https://api.github.com/repos/%v/%v/releases/tags/%v", owner, repo, version.Code), + nil, + ) + if err != nil { + panic(nil) + } + getReleaseRequest.Header.Set("User-Agent", ua) + getReleaseRequest.Header.Set("Authorization", ghToken) + getReleaseResponse, err := http.DefaultClient.Do(getReleaseRequest) + if err != nil { + panic(nil) + } + defer getReleaseResponse.Body.Close() + if getReleaseResponse.StatusCode == 404 { + url := fmt.Sprintf("https://api.github.com/repos/%v/%v/releases", owner, repo) + body := map[string]interface{}{ + "tag_name": version.Code, + "target_commitish": mainBranch, + "name": version.Code, + "body": version.Info, + "draft": true, + "prerelease": false, + } + var buff []byte + buff, err = json.Marshal(&body) + if err != nil { + panic(err) + } + var createReleaseRequest *http.Request + createReleaseRequest, err = http.NewRequest("POST", url, bytes.NewBuffer(buff)) + if err != nil { + panic(nil) + } + createReleaseRequest.Header.Set("User-Agent", ua) + createReleaseRequest.Header.Set("Authorization", ghToken) + var createReleaseResponse *http.Response + createReleaseResponse, err = http.DefaultClient.Do(createReleaseRequest) + if err != nil { + panic(nil) + } + defer createReleaseResponse.Body.Close() + if createReleaseResponse.StatusCode != 200 { + buff, err = ioutil.ReadAll(createReleaseResponse.Body) + if err != nil { + panic(nil) + } + println(string(buff)) + panic("NOT 200") + } + } +} diff --git a/ci/commons/types.go b/ci/commons/types.go new file mode 100644 index 0000000..ff449ea --- /dev/null +++ b/ci/commons/types.go @@ -0,0 +1,82 @@ +package commons + +import "time" + +type Version struct { + Code string `json:"code"` + Info string `json:"info"` +} + +type Release struct { + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + AssetsUrl string `json:"assets_url"` + UploadUrl string `json:"upload_url"` + TarballUrl string `json:"tarball_url"` + ZipballUrl string `json:"zipball_url"` + DiscussionUrl string `json:"discussion_url"` + Id int `json:"id"` + NodeId string `json:"node_id"` + TagName string `json:"tag_name"` + TargetCommitish string `json:"target_commitish"` + Name string `json:"name"` + Body string `json:"body"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` + CreatedAt time.Time `json:"created_at"` + PublishedAt time.Time `json:"published_at"` + Author struct { + Login string `json:"login"` + Id int `json:"id"` + NodeId string `json:"node_id"` + AvatarUrl string `json:"avatar_url"` + GravatarId string `json:"gravatar_id"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + FollowersUrl string `json:"followers_url"` + FollowingUrl string `json:"following_url"` + GistsUrl string `json:"gists_url"` + StarredUrl string `json:"starred_url"` + SubscriptionsUrl string `json:"subscriptions_url"` + OrganizationsUrl string `json:"organizations_url"` + ReposUrl string `json:"repos_url"` + EventsUrl string `json:"events_url"` + ReceivedEventsUrl string `json:"received_events_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } `json:"author"` + Assets []struct { + Url string `json:"url"` + BrowserDownloadUrl string `json:"browser_download_url"` + Id int `json:"id"` + NodeId string `json:"node_id"` + Name string `json:"name"` + Label string `json:"label"` + State string `json:"state"` + ContentType string `json:"content_type"` + Size int `json:"size"` + DownloadCount int `json:"download_count"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Uploader struct { + Login string `json:"login"` + Id int `json:"id"` + NodeId string `json:"node_id"` + AvatarUrl string `json:"avatar_url"` + GravatarId string `json:"gravatar_id"` + Url string `json:"url"` + HtmlUrl string `json:"html_url"` + FollowersUrl string `json:"followers_url"` + FollowingUrl string `json:"following_url"` + GistsUrl string `json:"gists_url"` + StarredUrl string `json:"starred_url"` + SubscriptionsUrl string `json:"subscriptions_url"` + OrganizationsUrl string `json:"organizations_url"` + ReposUrl string `json:"repos_url"` + EventsUrl string `json:"events_url"` + ReceivedEventsUrl string `json:"received_events_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } `json:"uploader"` + } `json:"assets"` +} \ No newline at end of file diff --git a/ci/go.mod b/ci/go.mod new file mode 100644 index 0000000..76812f9 --- /dev/null +++ b/ci/go.mod @@ -0,0 +1 @@ +module "ci" \ No newline at end of file diff --git a/ci/version.code.txt b/ci/version.code.txt new file mode 100644 index 0000000..87ff52e --- /dev/null +++ b/ci/version.code.txt @@ -0,0 +1 @@ +v1.4.2 \ No newline at end of file diff --git a/ci/version.info.txt b/ci/version.info.txt new file mode 100644 index 0000000..c1852c6 --- /dev/null +++ b/ci/version.info.txt @@ -0,0 +1 @@ +测试RELEASE \ No newline at end of file