From ef0fbeebe6695503cb9ebd92702ac591e3897989 Mon Sep 17 00:00:00 2001 From: khai96_ Date: Mon, 24 May 2021 09:27:48 +0700 Subject: [PATCH] ci: Setup deployment workflow --- .github/workflows/deploy.yaml | 456 ++++++++++++++++++ ci/github-actions/create-checksums.sh | 6 + ci/github-actions/expose-release-artifacts.sh | 21 + ci/github-actions/generate-pkgbuild.py3 | 58 +++ ci/github-actions/release-type.py3 | 52 ++ template/parallel-disk-usage-bin/PKGBUILD | 24 + template/parallel-disk-usage/PKGBUILD | 23 + 7 files changed, 640 insertions(+) create mode 100644 .github/workflows/deploy.yaml create mode 100755 ci/github-actions/create-checksums.sh create mode 100755 ci/github-actions/expose-release-artifacts.sh create mode 100755 ci/github-actions/generate-pkgbuild.py3 create mode 100755 ci/github-actions/release-type.py3 create mode 100644 template/parallel-disk-usage-bin/PKGBUILD create mode 100644 template/parallel-disk-usage/PKGBUILD diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..4cee3cd --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,456 @@ +name: Deployment + +on: + push: + tags: + - '*.*.*' + +jobs: + test: + name: Test + + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: true + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + components: clippy, rustfmt + override: 'true' + default: 'true' + + - name: Build (dev) + run: cargo build --locked + + - name: Test (dev) + run: cargo test + + - name: Build (release) + run: cargo build --locked --release + + - name: Test (release) + run: cargo test --release + + - name: Check formatting + if: runner.os == 'Linux' + run: cargo fmt -- --check + + - name: Clippy check (dev) + if: runner.os == 'Linux' + run: cargo clippy -- -D warnings + + - name: Clippy check (release) + if: runner.os == 'Linux' + run: cargo clippy --release -- -D warnings + + build_linux: + name: Build + + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + target: + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + target: ${{ matrix.target }} + override: 'true' + default: 'true' + + - name: Build + run: cargo build --target ${{ matrix.target }} --release + + - name: Strip all debug symbols + run: strip --strip-all target/${{ matrix.target }}/release/pdu + + - name: Upload build artifact + uses: actions/upload-artifact@v2 + with: + name: pdu-${{ matrix.target }} + path: target/${{ matrix.target }}/release/pdu + + build_macos: + name: Build + + runs-on: macos-latest + + strategy: + fail-fast: true + matrix: + target: + - x86_64-apple-darwin + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + target: ${{ matrix.target }} + override: 'true' + default: 'true' + + - name: Build + run: cargo build --target ${{ matrix.target }} --release + + - name: Strip all debug symbols + run: strip target/${{ matrix.target }}/release/pdu + + - name: Upload build artifact + uses: actions/upload-artifact@v2 + with: + name: pdu-${{ matrix.target }} + path: target/${{ matrix.target }}/release/pdu + + build_windows: + name: Build + + runs-on: windows-latest + + strategy: + fail-fast: true + matrix: + target: + - x86_64-pc-windows-gnu + - x86_64-pc-windows-msvc + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + target: ${{ matrix.target }} + override: 'true' + default: 'true' + + - name: Build + run: cargo build --target ${{ matrix.target }} --release + + - name: Upload build artifact + uses: actions/upload-artifact@v2 + with: + name: pdu-${{ matrix.target }} + path: target/${{ matrix.target }}/release/pdu.exe + + create_release: + name: Create Release + + needs: + - test + - build_linux + - build_macos + - build_windows + + runs-on: ubuntu-latest + + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + release_type: ${{ steps.release_type.outputs.release_type }} + is_release: ${{ steps.release_type.outputs.is_release }} + is_prerelease: ${{ steps.release_type.outputs.is_prerelease }} + release_tag: ${{ steps.release_type.outputs.release_tag }} + + steps: + - uses: actions/checkout@v2 + + - name: Install APT packages + run: sudo apt install -y python3 python3-toml + + - name: Determine release type + id: release_type + run: ./ci/github-actions/release-type.py3 + env: + RELEASE_TAG: ${{ github.ref }} + + - name: Create Release + id: create_release + if: steps.release_type.outputs.is_release == 'true' + uses: actions/create-release@v1.1.4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.release_type.outputs.release_tag }} + release_name: ${{ steps.release_type.outputs.release_tag }} + draft: 'false' + prerelease: ${{ steps.release_type.outputs.is_prerelease }} + + upload_generated_files: + name: Upload Generated Files + + needs: + - create_release + - test + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Upload Tab-Completion file for Bash + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./exports/completion.bash + asset_name: completion.bash + asset_content_type: text/plain + + - name: Upload Tab-Completion file for Fish + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./exports/completion.fish + asset_name: completion.fish + asset_content_type: text/plain + + - name: Upload Tab-Completion file for Zsh + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./exports/completion.zsh + asset_name: completion.zsh + asset_content_type: text/plain + + - name: Upload Tab-Completion file for PowerShell + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./exports/completion.ps1 + asset_name: completion.ps1 + asset_content_type: text/plain + + - name: Upload Tab-Completion file for Elvish + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./exports/completion.elv + asset_name: completion.elv + asset_content_type: text/plain + + upload_release_assets: + name: Upload Release Assets + + needs: + - create_release + - test + - build_linux + - build_macos + - build_windows + + runs-on: ubuntu-latest + + if: needs.create_release.outputs.is_release == 'true' + + strategy: + fail-fast: true + matrix: + target: + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + - x86_64-pc-windows-gnu + - x86_64-pc-windows-msvc + - x86_64-apple-darwin + + steps: + - uses: actions/checkout@v2 + + - name: Download artifact + uses: actions/download-artifact@v2.0.9 + with: + name: pdu-${{ matrix.target }} + + - name: Release executable (UNIX) + if: "!contains(matrix.target, 'windows')" + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./pdu + asset_name: pdu-${{ matrix.target }} + asset_content_type: application/x-pie-executable + + - name: Release executable (Windows) + if: contains(matrix.target, 'windows') + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./pdu.exe + asset_name: pdu-${{ matrix.target }}.exe + asset_content_type: application/x-dosexec + + upload_checksums: + name: Upload Checksums + + needs: + - create_release + - test + - build_linux + - build_macos + - build_windows + + if: needs.create_release.outputs.is_release == 'true' + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Download all artifacts + uses: actions/download-artifact@v2.0.9 + with: + path: ./downloads + + - name: Flatten directory + run: ./ci/github-actions/expose-release-artifacts.sh + + - name: Create checksums + run: ./ci/github-actions/create-checksums.sh + + - name: Upload as artifacts + uses: actions/upload-artifact@v2 + with: + name: checksums + path: sha*sum.txt + + - name: Release sha1sum + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./sha1sum.txt + asset_name: sha1sum.txt + asset_content_type: text/plain + + - name: Release sha256sum + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./sha256sum.txt + asset_name: sha256sum.txt + asset_content_type: text/plain + + - name: Release sha512sum + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: ./sha512sum.txt + asset_name: sha512sum.txt + asset_content_type: text/plain + + publish_aur_package: + name: Publish AUR package + + needs: + - create_release + - test + - build_linux + - upload_release_assets + + if: needs.create_release.outputs.release_type == 'official' + + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + target: + - x86_64-unknown-linux-gnu + + steps: + - uses: actions/checkout@v2 + + - name: Download checksums + uses: actions/download-artifact@v2.0.9 + with: + name: checksums + path: ./checksums + + - name: Generate PKGBUILD + env: + TARGET: ${{ matrix.target }} + RELEASE_TAG: ${{ needs.create_release.outputs.release_tag }} + run: ./ci/github-actions/generate-pkgbuild.py3 + + - name: Publish pdu to the AUR + uses: KSXGitHub/github-actions-deploy-aur@v2.2.4 + with: + pkgname: parallel-disk-usage + pkgbuild: ./pkgbuild/parallel-disk-usage/PKGBUILD + commit_username: ${{ secrets.AUR_USERNAME }} + commit_email: ${{ secrets.AUR_EMAIL }} + ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + commit_message: ${{ needs.create_release.outputs.release_tag }} + force_push: 'true' + + - name: Publish parallel-disk-usage-bin to the AUR + uses: KSXGitHub/github-actions-deploy-aur@v2.2.4 + with: + pkgname: parallel-disk-usage-bin + pkgbuild: ./pkgbuild/parallel-disk-usage-bin/PKGBUILD + commit_username: ${{ secrets.AUR_USERNAME }} + commit_email: ${{ secrets.AUR_EMAIL }} + ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + commit_message: ${{ needs.create_release.outputs.release_tag }} + force_push: 'true' + + publish_cargo_crate: + name: Publish Cargo crate + + needs: + - create_release + - test + + if: needs.create_release.outputs.release_type == 'official' + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + override: 'true' + default: 'true' + + - name: Login + run: cargo login ${{ secrets.CRATE_AUTH_TOKEN }} + + - name: Publish + run: cargo publish diff --git a/ci/github-actions/create-checksums.sh b/ci/github-actions/create-checksums.sh new file mode 100755 index 0000000..94be320 --- /dev/null +++ b/ci/github-actions/create-checksums.sh @@ -0,0 +1,6 @@ +#! /bin/bash +# shellcheck disable=SC2035 +cd ./flatten || exit $? +sha1sum * >../sha1sum.txt || exit $? +sha256sum * >../sha256sum.txt || exit $? +sha512sum * >../sha512sum.txt || exit $? diff --git a/ci/github-actions/expose-release-artifacts.sh b/ci/github-actions/expose-release-artifacts.sh new file mode 100755 index 0000000..fedcde0 --- /dev/null +++ b/ci/github-actions/expose-release-artifacts.sh @@ -0,0 +1,21 @@ +#! /bin/bash +mkdir ./flatten + +[ -d ./downloads ] || { + echo Folder ./downloads does not exist >/dev/stderr + exit 1 +} + +# shellcheck disable=SC2012 +ls ./downloads | while read -r name; do + case "$name" in + *wasm*) suffix=.wasm ;; + *windows*) suffix=.exe ;; + *) suffix='' ;; + esac + + src="./downloads/${name}/pdu${suffix}" + dst="./flatten/${name}${suffix}" + echo Copying "$src" to "$dst"... + cp "$src" "$dst" || exit $? +done diff --git a/ci/github-actions/generate-pkgbuild.py3 b/ci/github-actions/generate-pkgbuild.py3 new file mode 100755 index 0000000..d760240 --- /dev/null +++ b/ci/github-actions/generate-pkgbuild.py3 @@ -0,0 +1,58 @@ +#! /usr/bin/env python3 +from os import environ, makedirs +import re + +target = environ.get('TARGET') +if not target: + print('::error ::TARGET is required but missing') + exit(1) + +release_tag = environ.get('RELEASE_TAG') +if not release_tag: + print('::error ::RELEASE_TAG is required but missing') + exit(1) + +checksum = None +word_splitter = re.compile(r'\s+') +for line in open('checksums/sha1sum.txt').readlines(): + line = line.strip() + if line.endswith(target): + checksum, _ = word_splitter.split(line) + +maintainer = '# Maintainer: Hoàng Văn Khải \n' +readme_url = f'https://raw.githubusercontent.com/KSXGitHub/parallel-disk-usage/{release_tag}/README.md' +license_url = f'https://raw.githubusercontent.com/KSXGitHub/parallel-disk-usage/{release_tag}/LICENSE.md' + +opening = maintainer + '\n# This file is automatically generated. Do not edit.\n' + +print('Generating PKGBUILD for parallel-disk-usage...') +makedirs('./pkgbuild/parallel-disk-usage', exist_ok=True) +with open('./pkgbuild/parallel-disk-usage/PKGBUILD', 'w') as pkgbuild: + content = opening + '\n' + content += 'pkgname=parallel-disk-usage\n' + content += f'pkgver={release_tag}\n' + source_url = f'https://github.com/KSXGitHub/parallel-disk-usage/archive/{release_tag}.tar.gz' + content += f'source=(parallel-disk-usage-{release_tag}.tar.gz::{source_url})\n' + content += 'sha1sums=(SKIP)\n' + content += open('./template/parallel-disk-usage/PKGBUILD').read() + '\n' + pkgbuild.write(content) + +print('Generating PKGBUILD for parallel-disk-usage-bin...') +makedirs('./pkgbuild/parallel-disk-usage-bin', exist_ok=True) +with open('./pkgbuild/parallel-disk-usage-bin/PKGBUILD', 'w') as pkgbuild: + content = opening + '\n' + content += 'pkgname=parallel-disk-usage-bin\n' + content += f'pkgver={release_tag}\n' + source_url_prefix = f'https://github.com/KSXGitHub/parallel-disk-usage/releases/download/{release_tag}' + source_url = f'{source_url_prefix}/parallel-disk-usage-{target}' + supported_completions = ['bash', 'fish', 'zsh'] + completion_source = ' '.join( + f'completion.{release_tag}.{ext}::{source_url_prefix}/completion.{ext}' + for ext in supported_completions + ) + content += f'source=(pdu-{checksum}::{source_url} {completion_source} {readme_url} {license_url})\n' + content += f'_checksum={checksum}\n' + completion_checksums = ' '.join('SKIP' for _ in supported_completions) + content += f'_completion_checksums=({completion_checksums})\n' + content += open('./template/parallel-disk-usage-bin/PKGBUILD').read() + '\n' + pkgbuild.write(content) diff --git a/ci/github-actions/release-type.py3 b/ci/github-actions/release-type.py3 new file mode 100755 index 0000000..58c1f20 --- /dev/null +++ b/ci/github-actions/release-type.py3 @@ -0,0 +1,52 @@ +#! /usr/bin/env python3 +from os import environ +import re +import toml + +release_tag = environ.get('RELEASE_TAG', None) + +if not release_tag: + print('::error ::Environment variable RELEASE_TAG is required but missing') + exit(1) + +tag_prefix = 'refs/tags/' +if release_tag.startswith(tag_prefix): + release_tag = release_tag.replace(tag_prefix, '', 1) + +def dict_path(data, head: str, *tail: str): + if type(data) != dict: raise ValueError('Not a dict', data) + value = data.get(head) + if not tail: return value + return dict_path(value, *tail) + +with open('Cargo.toml') as cargo_toml: + data = toml.load(cargo_toml) + version = dict_path(data, 'package', 'version') + + if version != release_tag: + print(f'::warning ::RELEASE_TAG ({release_tag}) does not match Cargo.toml#package.version ({version})') + print('::set-output name=release_type::none') + print('::set-output name=is_release::false') + print('::set-output name=is_prerelease::false') + print(f'::set-output name=release_tag::{release_tag}') + exit(0) + +if re.match(r'^[0-9]+\.[0-9]+\.[0-9]+-.+$', release_tag): + print('::set-output name=release_type::prerelease') + print('::set-output name=is_release::true') + print('::set-output name=is_prerelease::true') + print(f'::set-output name=release_tag::{release_tag}') + exit(0) + +if re.match(r'^[0-9]+\.[0-9]+\.[0-9]+$', release_tag): + print('::set-output name=release_type::official') + print('::set-output name=is_release::true') + print('::set-output name=is_prerelease::false') + print(f'::set-output name=release_tag::{release_tag}') + exit(0) + +print('::set-output name=release_type::none') +print('::set-output name=is_release::false') +print('::set-output name=is_prerelease::false') +print(f'::set-output name=release_tag::{release_tag}') +exit(0) diff --git a/template/parallel-disk-usage-bin/PKGBUILD b/template/parallel-disk-usage-bin/PKGBUILD new file mode 100644 index 0000000..1b73bcc --- /dev/null +++ b/template/parallel-disk-usage-bin/PKGBUILD @@ -0,0 +1,24 @@ +# This PKGBUILD is not a full PKGBUILD +# pkgname, pkgver, source, and sha1sums are to be generated +pkgdesc='Create a filesystem tree from YAML' +pkgrel=1 +arch=(x86_64) +license=(MIT) +url='https://github.com/KSXGitHub/parallel-disk-usage' +provides=(parallel-disk-usage) +conflicts=(parallel-disk-usage) +sha1sums=( + "$_checksum" # for the pdu binary + "${_completion_checksums[@]}" # for the completion files + SKIP # for the readme file + SKIP # for the license file +) + +package() { + install -Dm755 "pdu-$_checksum" "$pkgdir/usr/bin/pdu" + install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md" + install -Dm644 LICENSE.md "$pkgdir/usr/share/licenses/$pkgname/LICENSE.md" + install -Dm644 "completion.$pkgver.bash" "$pkgdir/usr/share/bash-completion/completions/pdu" + install -Dm644 "completion.$pkgver.fish" "$pkgdir/usr/share/fish/completions/pdu.fish" + install -Dm644 "completion.$pkgver.zsh" "$pkgdir/usr/share/zsh/site-functions/_pdu" +} diff --git a/template/parallel-disk-usage/PKGBUILD b/template/parallel-disk-usage/PKGBUILD new file mode 100644 index 0000000..b2317d1 --- /dev/null +++ b/template/parallel-disk-usage/PKGBUILD @@ -0,0 +1,23 @@ +# This PKGBUILD is not a full PKGBUILD +# pkgname, pkgver, source, and sha1sums are to be generated +pkgdesc='Create a filesystem tree from YAML' +pkgrel=1 +arch=(x86_64) +license=(MIT) +url='https://github.com/KSXGitHub/parallel-disk-usage' +makedepends=(cargo) + +build() { + cd "$srcdir/parallel-disk-usage-$pkgver" + cargo build --release --locked --bin pdu +} + +package() { + cd "$srcdir/parallel-disk-usage-$pkgver" + install -Dm755 target/release/pdu "$pkgdir/usr/bin/pdu" + install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md" + install -Dm644 LICENSE.md "$pkgdir/usr/share/licenses/$pkgname/LICENSE.md" + install -Dm644 exports/completion.bash "$pkgdir/usr/share/bash-completion/completions/pdu" + install -Dm644 exports/completion.fish "$pkgdir/usr/share/fish/completions/pdu.fish" + install -Dm644 exports/completion.zsh "$pkgdir/usr/share/zsh/site-functions/_pdu" +}