diff --git a/.github/changelog.json b/.github/changelog.json new file mode 100644 index 0000000000..b8fb7b7629 --- /dev/null +++ b/.github/changelog.json @@ -0,0 +1,16 @@ +{ + "categories": [ + { + "title": "## Features", + "labels": ["T-feature"] + }, + { + "title": "## Fixes", + "labels": ["T-bug", "T-fix"] + } + ], + "ignore_labels": ["L-ignore"], + "template": "${{CHANGELOG}}\n## Other\n\n${{UNCATEGORIZED}}", + "pr_template": "- ${{TITLE}} (#${{NUMBER}})", + "empty_template": "- No changes" +} \ No newline at end of file diff --git a/.github/scripts/create-tag.js b/.github/scripts/create-tag.js new file mode 100644 index 0000000000..6ecd0bc9a8 --- /dev/null +++ b/.github/scripts/create-tag.js @@ -0,0 +1,14 @@ +module.exports = async ({ github, context }, tagName) => { + try { + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${tagName}`, + sha: context.sha, + force: true, + }); + } catch (err) { + console.error(`Failed to create tag: ${tagName}`); + console.error(err); + } +}; \ No newline at end of file diff --git a/.github/scripts/move-tag.js b/.github/scripts/move-tag.js new file mode 100644 index 0000000000..580fa58e75 --- /dev/null +++ b/.github/scripts/move-tag.js @@ -0,0 +1,15 @@ +module.exports = async ({ github, context }, tagName) => { + try { + await github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tagName}`, + sha: context.sha, + force: true, + }); + } catch (err) { + console.error(`Failed to move nightly tag.`); + console.error(`This should only happen the first time.`); + console.error(err); + } +}; \ No newline at end of file diff --git a/.github/scripts/prune-prereleases.js b/.github/scripts/prune-prereleases.js new file mode 100644 index 0000000000..0537fbf138 --- /dev/null +++ b/.github/scripts/prune-prereleases.js @@ -0,0 +1,39 @@ +module.exports = async ({ github, context }) => { + console.log("Pruning old prereleases"); + + // doc: https://docs.github.com/en/rest/releases/releases + const { data: releases } = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + + let nightlies = releases.filter( + release => + // Only consider releases tagged `nightly-${SHA}` for deletion + release.tag_name.includes("nightly") && + release.tag_name !== "nightly" && + // ref: https://github.com/foundry-rs/foundry/issues/3881 + // Skipping pruning the build on 1st day of each month + !release.created_at.includes("-01T") + ); + + // Keep newest 3 nightlies + nightlies = nightlies.slice(3); + + for (const nightly of nightlies) { + console.log(`Deleting nightly: ${nightly.tag_name}`); + await github.rest.repos.deleteRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: nightly.id, + }); + console.log(`Deleting nightly tag: ${nightly.tag_name}`); + await github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${nightly.tag_name}`, + }); + } + + console.log("Done."); +}; diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1f461e0029..17d40da985 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,58 +3,205 @@ name: release on: push: tags: - - '*' + - "*" + +env: + IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + CARGO_TERM_COLOR: always jobs: + prepare: + name: Prepare release + runs-on: ubuntu-20.04 + + outputs: + tag_name: ${{ steps.release_info.outputs.tag_name }} + release_name: ${{ steps.release_info.outputs.release_name }} + changelog: ${{ steps.build_changelog.outputs.changelog }} + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Compute release name and tag + id: release_info + run: | + if [[ $IS_NIGHTLY ]]; then + echo "::set-output name=tag_name::nightly-${GITHUB_SHA}" + echo "::set-output name=release_name::Nightly ($(date '+%Y-%m-%d'))" + else + echo "::set-output name=tag_name::${GITHUB_REF_NAME}" + echo "::set-output name=release_name::${GITHUB_REF_NAME}" + fi + + # Creates a `nightly-SHA` tag for this specific nightly + # This tag is used for this specific nightly version's release + # which allows users to roll back. It is also used to build + # the changelog. + - name: Create build-specific nightly tag + if: ${{ env.IS_NIGHTLY }} + uses: actions/github-script@v5 + env: + TAG_NAME: ${{ steps.release_info.outputs.tag_name }} + with: + script: | + const createTag = require('./.github/scripts/create-tag.js') + await createTag({ github, context }, process.env.TAG_NAME) + + - name: Build changelog + id: build_changelog + uses: mikepenz/release-changelog-builder-action@v2 + with: + configuration: "./.github/changelog.json" + fromTag: ${{ env.IS_NIGHTLY && 'nightly' || '' }} + toTag: ${{ steps.release_info.outputs.tag_name }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + release: name: Release for ${{ matrix.os }} + needs: prepare runs-on: ${{ matrix.os }} strategy: matrix: - include: - - os: ubuntu-latest - artifact_name: dojo-linux-x86_64.tar.gz - asset_name: dojo-linux-x86_64.tar.gz + job: + # The OS is used for the runner + # The platform is a generic platform name + # The target is used by Cargo + # The arch is either 386, arm64 or amd64 + # The svm target platform to use for the binary https://github.com/roynalnaruto/svm-rs/blob/84cbe0ac705becabdc13168bae28a45ad2299749/svm-builds/build.rs#L4-L24 + - os: ubuntu-20.04 + platform: linux + target: x86_64-unknown-linux-gnu + arch: amd64 + svm_target_platform: linux-amd64 + - os: ubuntu-20.04 + platform: linux + target: aarch64-unknown-linux-gnu + arch: arm64 + svm_target_platform: linux-aarch64 + - os: macos-latest + platform: darwin + target: x86_64-apple-darwin + arch: amd64 + svm_target_platform: macosx-amd64 - os: macos-latest - artifact_name: dojo-darwin-x86_64.tar.gz - asset_name: dojo-darwin-x86_64.tar.gz + platform: darwin + target: aarch64-apple-darwin + arch: arm64 + svm_target_platform: macosx-aarch64 + - os: windows-latest + platform: win32 + target: x86_64-pc-windows-msvc + arch: amd64 + svm_target_platform: windows-amd64 steps: - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - name: Rust Toolchain Setup - with: - profile: minimal - toolchain: nightly-2022-11-03 - - - uses: Swatinem/rust-cache@v2 - - uses: arduino/setup-protoc@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - - name: Build - run: | - cargo build --release --locked - - - name: Create Tarball - run: > - tar -C target/release -czvf ${{ matrix.artifact_name }} - dojo dojo-indexer dojo-language-server dojo-test - - - name: Upload Binaries - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ matrix.artifact_name }} - asset_name: ${{ matrix.asset_name }} - tag: ${{ github.ref }} + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + name: Rust Toolchain Setup + with: + profile: minimal + toolchain: nightly-2022-11-03 + target: ${{ matrix.job.target }} + override: true + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: Apple M1 setup + if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} + run: | + echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV + echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV + + - name: Linux ARM setup + if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }} + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-aarch64-linux-gnu + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + + - name: Build binaries + uses: actions-rs/cargo@v1 + env: + SVM_TARGET_PLATFORM: ${{ matrix.job.svm_target_platform }} + with: + command: build + args: --release --bins --target ${{ matrix.job.target }} + + - name: Archive binaries + id: artifacts + env: + PLATFORM_NAME: ${{ matrix.job.platform }} + TARGET: ${{ matrix.job.target }} + ARCH: ${{ matrix.job.arch }} + VERSION_NAME: ${{ (env.IS_NIGHTLY && 'nightly') || needs.prepare.outputs.tag_name }} + run: | + if [ "$PLATFORM_NAME" == "linux" ]; then + tar -czvf "dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release dojo + echo "::set-output name=file_name::dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" + elif [ "$PLATFORM_NAME" == "darwin" ]; then + # We need to use gtar here otherwise the archive is corrupt. + # See: https://github.com/actions/virtual-environments/issues/2619 + gtar -czvf "dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release dojo + echo "::set-output name=file_name::dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" + else + cd ./target/${TARGET}/release + 7z a -tzip "dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" dojo + mv "dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" ../../../ + echo "::set-output name=file_name::dojo_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" + fi + shell: bash + + # Creates the release for this specific version + - name: Create release + uses: softprops/action-gh-release@v1 + with: + name: ${{ needs.prepare.outputs.release_name }} + tag_name: ${{ needs.prepare.outputs.tag_name }} + prerelease: ${{ env.IS_NIGHTLY }} + body: ${{ needs.prepare.outputs.changelog }} + files: | + ${{ steps.artifacts.outputs.file_name }} + + # If this is a nightly release, it also updates the release + # tagged `nightly` for compatibility with `dojoup` + - name: Update nightly release + if: ${{ env.IS_NIGHTLY }} + uses: softprops/action-gh-release@v1 + with: + name: "Nightly" + tag_name: "nightly" + prerelease: true + body: ${{ needs.prepare.outputs.changelog }} + files: | + ${{ steps.artifacts.outputs.file_name }} + + cleanup: + name: Release cleanup + runs-on: ubuntu-20.04 + needs: release + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + # Moves the `nightly` tag to `HEAD` + - name: Move nightly tag + if: ${{ env.IS_NIGHTLY }} + uses: actions/github-script@v5 + with: + script: | + const moveTag = require('./.github/scripts/move-tag.js') + await moveTag({ github, context }, 'nightly') + + - name: Delete old nightlies + uses: actions/github-script@v5 + with: + script: | + const prunePrereleases = require('./.github/scripts/prune-prereleases.js') + await prunePrereleases({github, context})