Goreleaser 使用介绍

发布时间: 更新时间: 总字数:4451 阅读时间:9m 作者: IP:上海 网址

GoReleaser 是快速、轻松地发布 Go 项目的首选工具,支持与 github actions 集成

介绍

GoReleaser 功能:

  • 交叉编译 Go 项目
  • 发布 release 到 GitHub、GitLab 和 Gitea
  • 支持夜间构建(nightly builds)
  • 创建 Docker 镜像和清单
  • 创建 Linux 软件包和 Homebrew taps
  • 签署制品(Sign artifacts)、校验(checksums)和及容器镜像(container images)
  • 在 Twitter、Slack、Discord 等平台上发布新版本信息
  • 为二进制文件和容器镜像生成 SBOMs(Software Bill of Materials)

GoReleaser 有两个版本:

  • OSS: 开源免费版本(本文示例使用)
  • Pro: 需要 license

安装

# mac
brew install goreleaser/tap/goreleaser
brew install goreleaser

# snapcraft
sudo snap install --classic goreleaser

# apt
echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
sudo apt update
sudo apt install goreleaser

# go
go install github.com/goreleaser/goreleaser/v2@latest
# go install github.com/goreleaser/goreleaser@v1.25.1

# bash
curl -sfL https://goreleaser.com/static/run | bash
  • version
$ goreleaser -v
  ____       ____      _
 / ___| ___ |  _ \ ___| | ___  __ _ ___  ___ _ __
| |  _ / _ \| |_) / _ \ |/ _ \/ _` / __|/ _ \ '__|
| |_| | (_) |  _ <  __/ |  __/ (_| \__ \  __/ |
 \____|\___/|_| \_\___|_|\___|\__,_|___/\___|_|
goreleaser: Deliver Go Binaries as fast and easily as possible
https://goreleaser.com

GitVersion:    2.0.1
GitCommit:     684c1805864e5f29acc204e34e1770eb74918d15
GitTreeState:  false
BuildDate:     2024-06-11T01:45:52Z
BuiltBy:       goreleaser
GoVersion:     go1.22.4
Compiler:      gc
ModuleSum:     h1:Wx2peRnvixEBRKxU6T0Gh+3wlire+Jv2IOW5eNPan3U=
Platform:      darwin/amd64

help

goreleaser --help ...
  • goreleaser build --help
  • goreleaser release --help

使用

$ goreleaser init
  • Generating .goreleaser.yaml file
  • config created; please edit accordingly to your needs file=.goreleaser.yaml
  • thanks for using goreleaser!
$ cat .goreleaser.yaml
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com

# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 2

before:
  hooks:
    # You may remove this if you don't use go modules.
    - go mod tidy
    # you may remove this if you don't need go generate
    - go generate ./...

builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin

archives:
  - format: tar.gz
    # this name template makes the OS and Arch compatible with the results of `uname`.
    name_template: >-
      {{ .ProjectName }}_
      {{- title .Os }}_
      {{- if eq .Arch "amd64" }}x86_64
      {{- else if eq .Arch "386" }}i386
      {{- else }}{{ .Arch }}{{ end }}
      {{- if .Arm }}v{{ .Arm }}{{ end }}
    # use zip for windows archives
    format_overrides:
      - goos: windows
        format: zip

changelog:
  sort: asc
  filters:
    exclude:
      - "^docs:"
      - "^test:"

二进制名称字段支持模板化。可显示以下构建细节:

Key Description
.Os GOOS
.Arch GOARCH
.Arm GOARM
.Ext Extension, e.g. .exe
.Target Build target, e.g. darwin_amd64
  • local-only 发布
goreleaser release --snapshot --clean
  • 检查配置文件是否正常
goreleaser check
  • 使用 GoReleaser 只为指定的 GOOS/GOARCH 生成二进制文件
goreleaser build --single-target
export GITHUB_TOKEN="YOUR_GH_TOKEN"

# GoReleaser will use the latest Git tag of your repository.
git tag -a v0.1.0 -m "First release"
git push origin v0.1.0

# it will create a release on GitHub with all the artifacts
goreleaser release

如果还不想创建标签,也可以使用 --snapshot 标记,在不发布最新提交的情况下运行 GoReleaser:

goreleaser release --snapshot
  • --skip=publish 跳过发布
goreleaser release --skip=publish
# .goreleaser.yaml
before:
  hooks:
    - go mod tidy
# rest of the file...

Linux packages

nfpms-.goreleaser.yaml ...

nfpm 介绍

echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
sudo apt update
sudo apt install nfpm

go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
# 初始化配置文件,参考https://nfpm.goreleaser.com/configuration/
nfpm init
nfpm pkg --packager deb --target /tmp/
nfpm pkg --packager rpm --target /tmp/

DMG

  • DMG for macos

MSI

  • MSI for windows

Snapcraft Packages (snaps)

Docker Images

配置示例

golang

---
version: 2
project_name: go-actions-demo

before:
  hooks:
    # You may remove this if you don't use go modules.
    - go mod tidy
    # you may remove this if you don't need go generate
    - go generate ./...

builds:
  - binary: go-actions-demo
    main: ./cmd/go-actions-demo/
    flags:
      - -trimpath
    ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{.Date}}
    env:
      - CGO_ENABLED=0
    goos:
      - darwin
      - windows
      - linux
      - freebsd
      - netbsd
      - illumos
    goarch:
      - amd64
      - arm64
      - arm
      - 386
      - ppc64le
      - s390x
      - mips64
      - mips64le
      - riscv64
      - loong64
    goarm:
      - 6
      - 7
    gomips:
      - hardfloat
    ignore:
      - goos: darwin
        goarch: 386
      - goos: freebsd
        goarch: arm64

archives:
  - format: tar.gz
    wrap_in_directory: true
    format_overrides:
      - goos: windows
        format: zip
    name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
    files:
      - LICENSE
      - README.md

snapshot:
  name_template: SNAPSHOT-{{ .Commit }}

checksum:
  name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'

changelog:
  sort: asc
  filters:
    exclude:
      - '(?i)^docs?:'
      - '(?i)^docs\([^:]+\):'
      - '(?i)^docs\[[^:]+\]:'
      - '^tests?:'
      - '(?i)^dev:'
      - '(?i)^chore:'
      - '^build\(deps\): bump .* in /docs \(#\d+\)'
      - '^build\(deps\): bump .* in /\.github/peril \(#\d+\)'
      - '^build\(deps\): bump .* in /scripts/gen_github_action_config \(#\d+\)'
      - Merge pull request
      - Merge branch

release:
  github:
    owner: xiexianbin
    name: go-actions-demo
  header: |
    `go-actions-demo` is a free and open-source project built by volunteers.

    If you value it, consider supporting us, the maintainers.

    We appreciate it! :heart:

    For key updates, see the [changelog](https://github.com/xiexianbin/go-actions-demo/releases/tag/v{{ .Major }}{{ .Minor }}{{ .Patch }}).

source:
  enabled: true
  name_template: '{{ .ProjectName }}-{{ .Version }}-source'

brews:
  - repository:
      owner: xiexianbin
      name: homebrew-tap
    directory: Formula
    homepage: https://xiexianbin.cn
    description: go actions demo.
    install: |
      bin.install "go-actions-demo"
      output = Utils.popen_read("#{bin}/go-actions-demo completion bash")
      (bash_completion/"go-actions-demo").write output
      output = Utils.popen_read("#{bin}/go-actions-demo completion zsh")
      (zsh_completion/"_go-actions-demo").write output
      output = Utils.popen_read("#{bin}/go-actions-demo completion fish")
      (fish_completion/"go-actions-demo.fish").write output
      prefix.install_metafiles
    test: |
      system "#{bin}/go-actions-demo --version"

chocolateys:
  - name: go-actions-demo
    owners: xiexianbin
    title: go-actions-demo
    authors: xiexianbin
    project_url: https://github.com/xiexianbin/go-actions-demo
    url_template: "https://github.com/xiexianbin/go-actions-demo/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
    icon_url: "https://www.xiexianbin.cn/images/logo/logo.png"
    copyright: xiexianbin.cn
    license_url: https://github.com/xiexianbin/go-actions-demo/blob/main/LICENSE
    require_license_acceptance: false
    project_source_url: https://github.com/xiexianbin/go-actions-demo
    package_source_url: https://github.com/xiexianbin/go-actions-demo
    docs_url: https://github.com/xiexianbin/go-actions-demo
    bug_tracker_url: https://github.com/xiexianbin/go-actions-demo/issues
    tags: "go golang lint linter"
    summary: go actions demo
    description: |
      {{ .ProjectName }} installer package.
      go actions demo .
    release_notes: "https://github.com/xiexianbin/go-actions-demo/releases/tag/v{{ .Version }}"
    api_key: "{{ .Env.CHOCOLATEY_API_KEY }}"
    source_repo: "https://push.chocolatey.org/"
    skip_publish: false
    goamd64: v1

nfpms:
  -
    id: go-actions-demo-nfpms
    package_name: go-actions-demo
    file_name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    homepage: https://github.com/xiexianbin/go-actions-demo/
    maintainer: "xiexianbin <me@xiexianbin.cn>"
    description: go-actions-demo
    license:  Apache-2.0 license
    section: golang
    formats:
      - deb
      - rpm
      - apk
    umask: 0o022
    overrides:
      deb:
        contents:
          - src: LICENSE
            dst: /usr/share/doc/go-actions-demo/copyright
          - src: README.md
            dst: /usr/share/doc/go-actions-demo/README.md
        recommends:
          - golang-go
      rpm:
        contents:
          - src: LICENSE
            dst: /usr/share/doc/go-actions-demo/LICENSE
            type: license
          - src: README.md
            dst: /usr/share/doc/go-actions-demo/README.md
            type: readme
        recommends:
          - /usr/bin/go
    rpm:
      group: Development/Tools

docker_manifests:
  # basic
  - name_template: 'xiexianbin/go-actions-demo:latest'
    image_templates:
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-arm64'

  - name_template: 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}'
    image_templates:
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-amd64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-arm64'

  - name_template: 'xiexianbin/go-actions-demo:{{ .Tag }}'
    image_templates:
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-arm64'

  # alpine
  - name_template: 'xiexianbin/go-actions-demo:latest-alpine'
    image_templates:
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-arm64'

  - name_template: 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-alpine'
    image_templates:
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-alpine-amd64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-alpine-arm64'

  - name_template: 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine'
    image_templates:
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-arm64'

dockers:
  - use: buildx
    goos: linux
    goarch: amd64
    dockerfile: build/buildx.Dockerfile
    image_templates:
      - 'xiexianbin/go-actions-demo:latest-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-amd64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-amd64'
    build_flag_templates:
      - '--pull'
      # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
      - '--label=org.opencontainers.image.title={{.ProjectName}}'
      - '--label=org.opencontainers.image.description=go actions demo'
      - '--label=org.opencontainers.image.source={{.GitURL}}'
      - '--label=org.opencontainers.image.url={{.GitURL}}'
      - '--label=org.opencontainers.image.documentation=https://github.com/xiexianbin/go-actions-demo'
      - '--label=org.opencontainers.image.created={{.Date}}'
      - '--label=org.opencontainers.image.revision={{.FullCommit}}'
      - '--label=org.opencontainers.image.version={{.Version}}'
      - '--platform=linux/amd64'

  - use: buildx
    goos: linux
    goarch: arm64
    dockerfile: build/buildx.Dockerfile
    image_templates:
      - 'xiexianbin/go-actions-demo:latest-arm64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-arm64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-arm64'
    build_flag_templates:
      - '--pull'
      # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
      - '--label=org.opencontainers.image.title={{.ProjectName}}'
      - '--label=org.opencontainers.image.description=go actions demo'
      - '--label=org.opencontainers.image.source={{.GitURL}}'
      - '--label=org.opencontainers.image.url={{.GitURL}}'
      - '--label=org.opencontainers.image.documentation=https://github.com/xiexianbin/go-actions-demo'
      - '--label=org.opencontainers.image.created={{.Date}}'
      - '--label=org.opencontainers.image.revision={{.FullCommit}}'
      - '--label=org.opencontainers.image.version={{.Version}}'
      - '--platform=linux/arm64'

  - use: buildx
    goos: linux
    goarch: amd64
    dockerfile: build/buildx-alpine.Dockerfile
    image_templates:
      - 'xiexianbin/go-actions-demo:latest-alpine-amd64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-amd64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-alpine-amd64'
    build_flag_templates:
      - '--pull'
      # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
      - '--label=org.opencontainers.image.title={{.ProjectName}}'
      - '--label=org.opencontainers.image.description=go actions demo'
      - '--label=org.opencontainers.image.source={{.GitURL}}'
      - '--label=org.opencontainers.image.url={{.GitURL}}'
      - '--label=org.opencontainers.image.documentation=https://github.com/xiexianbin/go-actions-demo'
      - '--label=org.opencontainers.image.created={{.Date}}'
      - '--label=org.opencontainers.image.revision={{.FullCommit}}'
      - '--label=org.opencontainers.image.version={{.Version}}'
      - '--platform=linux/amd64'

  - use: buildx
    goos: linux
    goarch: arm64
    dockerfile: build/buildx-alpine.Dockerfile
    image_templates:
      - 'xiexianbin/go-actions-demo:latest-alpine-arm64'
      - 'xiexianbin/go-actions-demo:{{ .Tag }}-alpine-arm64'
      - 'xiexianbin/go-actions-demo:v{{ .Major }}.{{ .Minor }}-alpine-arm64'
    build_flag_templates:
      - '--pull'
      # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
      - '--label=org.opencontainers.image.title={{.ProjectName}}'
      - '--label=org.opencontainers.image.description=go actions demo'
      - '--label=org.opencontainers.image.source={{.GitURL}}'
      - '--label=org.opencontainers.image.url={{.GitURL}}'
      - '--label=org.opencontainers.image.documentation=https://github.com/xiexianbin/go-actions-demo'
      - '--label=org.opencontainers.image.created={{.Date}}'
      - '--label=org.opencontainers.image.revision={{.FullCommit}}'
      - '--label=org.opencontainers.image.version={{.Version}}'
      - '--platform=linux/arm64'

与其他工具集成

Makefile

.PHONY: release-dry-run
release-dry-run:
	goreleaser release --clean --auto-snapshot --skip-validate --skip-publish --debug

.PHONY: release-build
release-build:
	goreleaser build --clean --skip-validate --snapshot --debug

github actions

  • tag.yml
name: "Release a tag"
on:
  push:
    tags:
      - v*

jobs:
  release:
    runs-on: ubuntu-latest
    env:
      # https://github.com/actions/setup-go#supported-version-syntax
      # ex:
      # - 1.18beta1 -> 1.18.0-beta.1
      # - 1.18rc1 -> 1.18.0-rc.1
      GO_VERSION: '1.22'
      CHOCOLATEY_VERSION: 2.2.0
    steps:
      - uses: actions/checkout@v4
      - name: Install Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
      - name: Unshallow
        run: git fetch --prune --unshallow

      - name: Install chocolatey
        run: |
          mkdir -p /opt/chocolatey
          wget -q -O - "https://github.com/chocolatey/choco/releases/download/${CHOCOLATEY_VERSION}/chocolatey.v${CHOCOLATEY_VERSION}.tar.gz" | tar -xz -C "/opt/chocolatey"
          echo '#!/bin/bash' >> /usr/local/bin/choco
          echo 'mono /opt/chocolatey/choco.exe $@' >> /usr/local/bin/choco
          chmod +x /usr/local/bin/choco

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login do docker.io
        run: docker login -u golangci -p ${{ secrets.DOCKER_TOKEN }}

      - name: Create release
        uses: goreleaser/goreleaser-action@v6
        with:
          version: latest
          args: release --clean --timeout=90m
        env:
          CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  • release-dry-run.yml
name: Release (Dry Run)

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    branches:
      - main
      - release-*
  merge_group:
    branches:
    - main

jobs:
  goreleaser:
    name: Release (Dry Run)
    needs: skip-check
    if: ${{ needs.skip-check.outputs.should_skip != 'true' }}
    runs-on: ubuntu-latest
    timeout-minutes: 40
    permissions:
      contents: read
    env:
      DOCKER_CLI_EXPERIMENTAL: "enabled"
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-gov4
        with:
          go-version-file: .go-version

      - name: Set up Snapcraft
        run: |
          sudo snap install snapcraft --channel=7.x/stable --classic
          # See https://github.com/goreleaser/goreleaser/issues/1715
          mkdir -p "$HOME/.cache/snapcraft/download"
          mkdir -p "$HOME/.cache/snapcraft/stage-packages"

      - name: Validate
        uses: goreleaser/goreleaser-action@v4
        with:
          distribution: goreleaser
          version: ${{ env.GORELEASER_VERSION }}
          args: check

      - name: Set Tag
        run: |
          echo "goreleaser_current_tag=`git describe --match 'v*' --tags`" >> $GITHUB_ENV

      - name: Dry Run
        uses: goreleaser/goreleaser-action@v4
        with:
          distribution: goreleaser
          version: ${{ env.GORELEASER_VERSION }}
          args: release --clean --skip-validate --skip-publish --timeout=60m
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GORELEASER_CURRENT_TAG: "${{ env.goreleaser_current_tag }}"
  • release.yml
name: Goreleaser

on:
  push:
    tags:
      - v*

env:
  # renovate: datasource=go depName=github.com/goreleaser/goreleaser
  GORELEASER_VERSION: v2.0.1

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    timeout-minutes: 45
    env:
      DOCKER_CLI_EXPERIMENTAL: "enabled"
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version-file: .go-version

      - uses: pnpm/action-setup@v3
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Set up Snapcraft
        run: |
          sudo snap install snapcraft --channel=7.x/stable --classic
          # See https://github.com/goreleaser/goreleaser/issues/1715
          mkdir -p "$HOME/.cache/snapcraft/download"
          mkdir -p "$HOME/.cache/snapcraft/stage-packages"

      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v4
        if: startsWith(github.ref, 'refs/tags/')
        with:
          distribution: goreleaser
          version: ${{ env.GORELEASER_VERSION }}
          args: release --clean --timeout=60m
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Archive generated artifacts
        uses: actions/upload-artifact@v3
        with:
          name: go-actions-demo-dist-release
          if-no-files-found: error
          path: |
            dist
            !dist/*.txt

  container:
    name: Build and release container images
    runs-on: ubuntu-latest
    timeout-minutes: 30
    needs: release
    container:
      # https://github.com/containers/podman/tree/main/contrib/podmanimage
      image: quay.io/containers/podman:v4.9.4
      options: >-
        --device /dev/fuse:rw
        --privileged
        --security-opt label=disable
        --security-opt seccomp=unconfined
    permissions:
      id-token: write
      packages: write
      contents: read

    steps:
      - name: Install dependencies
        run: dnf install --assumeyes --repo fedora git make jq

      - name: Check out code into the Go module directory
        uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:
          name: go-actions-demo-dist-release
          path: dist

      - name: Get branch name
        shell: bash
        run: echo "GITHUB_BRANCH_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV

      - name: Build container
        run: make container

      - name: Check images created
        run: podman images | grep 'ghcr.io/xiexianbin/go-actions-demo'

      - name: Login to registry
        run: |
          echo "${{ secrets.PERSONAL_ACCESS_TOKEN }}" | podman login -u xiexianbin --password-stdin ghcr.io

      - name: Install cosign
        uses: sigstore/cosign-installer@v3

      - name: Install crane
        uses: imjasonh/setup-crane@v0.3

      - name: Push container
        run: |
          make push-container

      - name: Sign container
        run: |
          make sign-container

  snap:
    runs-on: ubuntu-latest
    needs: release
    timeout-minutes: 30
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: go-actions-demo-dist-release
          path: dist

      - name: Install snapcraft
        run: |
          sudo snap install snapcraft --classic --channel=7.x/stable

      - name: Release to latest/edge
        env:
          SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
        run: |
          snapcraft upload dist/*_amd64.snap --release stable
          snapcraft upload dist/*_arm64.snap --release stable
本文总阅读量 次 本站总访问量 次 本站总访客数