Skip to content

feat: add support for configuring branch name prefix #117

feat: add support for configuring branch name prefix

feat: add support for configuring branch name prefix #117

Workflow file for this run

name: PR Build
on:
pull_request_target:
types: [opened, synchronize, reopened]
jobs:
build-linux:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.VERSION }}
pr_number: ${{ steps.version.outputs.PR_NUMBER }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
targets: x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu
- name: Install cross-compilation tools
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Set PR version
id: version
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
COMMIT_SHA=${{ github.event.pull_request.head.sha }}
COMMIT_SHA=${COMMIT_SHA::7}
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
PR_VERSION="${CARGO_VERSION}-pr.${PR_NUMBER}.${COMMIT_SHA}"
echo "VERSION=$PR_VERSION" >> $GITHUB_OUTPUT
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "Generated PR version: ${PR_VERSION}"
sed -i "s/^version = \".*\"/version = \"${PR_VERSION}\"/" Cargo.toml
- name: Format check
run: cargo fmt --all -- --check
- name: Build for Linux x64
run: cargo build --release --target x86_64-unknown-linux-gnu
- name: Build for Linux ARM64
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: cargo build --release --target aarch64-unknown-linux-gnu
- name: Prepare artifacts
run: |
cp target/x86_64-unknown-linux-gnu/release/grove grove-linux-x64
cp target/aarch64-unknown-linux-gnu/release/grove grove-linux-arm64
- name: Upload Linux executables
uses: actions/upload-artifact@v4
with:
name: grove-linux-executables
path: |
grove-linux-x64
grove-linux-arm64
retention-days: 1
build-macos:
runs-on: macos-latest
needs: build-linux
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-apple-darwin,aarch64-apple-darwin
- name: Set version
run: sed -i '' "s/^version = \".*\"/version = \"${{ needs.build-linux.outputs.version }}\"/" Cargo.toml
- name: Build for macOS x64
run: cargo build --release --target x86_64-apple-darwin
- name: Build for macOS ARM64
run: cargo build --release --target aarch64-apple-darwin
- name: Prepare artifacts
run: |
cp target/x86_64-apple-darwin/release/grove grove-darwin-x64
cp target/aarch64-apple-darwin/release/grove grove-darwin-arm64
- name: Import Code Signing Certificate
env:
MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }}
MACOS_CERT_P12_PASSWORD: ${{ secrets.MACOS_CERT_P12_PASSWORD }}
run: |
# Create a temporary keychain
KEYCHAIN_PATH=$RUNNER_TEMP/signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
# Decode the certificate
echo "$MACOS_CERT_P12_BASE64" | base64 --decode > $RUNNER_TEMP/certificate.p12
# Create and configure keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate
security import $RUNNER_TEMP/certificate.p12 -P "$MACOS_CERT_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# Clean up certificate file
rm $RUNNER_TEMP/certificate.p12
- name: Sign macOS Binaries
run: |
# Find the signing identity
IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}')
echo "Signing with identity: $IDENTITY"
# Sign both binaries with JIT entitlements
codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-x64
codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-arm64
# Verify signatures
codesign --verify --verbose grove-darwin-x64
codesign --verify --verbose grove-darwin-arm64
- name: Notarize macOS Binaries
env:
APPLE_ID_EMAIL: ${{ secrets.APPLE_ID_EMAIL }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
run: |
# Create zip files for notarization
zip grove-darwin-x64.zip grove-darwin-x64
zip grove-darwin-arm64.zip grove-darwin-arm64
# Get team ID from signing identity
TEAM_ID=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*(\([A-Z0-9]*\)).*/\1/p')
# Notarize x64 binary
xcrun notarytool submit grove-darwin-x64.zip \
--apple-id "$APPLE_ID_EMAIL" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$TEAM_ID" \
--wait
# Notarize ARM64 binary
xcrun notarytool submit grove-darwin-arm64.zip \
--apple-id "$APPLE_ID_EMAIL" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$TEAM_ID" \
--wait
# Clean up zip files
rm grove-darwin-x64.zip grove-darwin-arm64.zip
- name: Upload macOS executables
uses: actions/upload-artifact@v4
with:
name: grove-macos-executables
path: |
grove-darwin-x64
grove-darwin-arm64
retention-days: 1
build-windows:
runs-on: windows-latest
needs: build-linux
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Set version
shell: pwsh
run: |
$version = '${{ needs.build-linux.outputs.version }}'
(Get-Content Cargo.toml -Raw) `
-replace '^(version = ").*(")$', "`$1$version`$2" |
Set-Content Cargo.toml
- name: Build for Windows x64
run: cargo build --release --target x86_64-pc-windows-msvc
- name: Prepare artifacts
run: |
copy target\x86_64-pc-windows-msvc\release\grove.exe grove-windows-x64.exe
- name: Upload Windows executable
uses: actions/upload-artifact@v4
with:
name: grove-windows-executable
path: |
grove-windows-x64.exe
retention-days: 1
publish-pr:
runs-on: ubuntu-latest
needs: [build-linux, build-macos, build-windows]
permissions:
contents: read
pull-requests: write
actions: write
steps:
- name: Download Linux executables
uses: actions/download-artifact@v4
with:
name: grove-linux-executables
path: ./executables
- name: Download macOS executables
uses: actions/download-artifact@v4
with:
name: grove-macos-executables
path: ./executables
- name: Download Windows executables
uses: actions/download-artifact@v4
with:
name: grove-windows-executable
path: ./executables
- name: Upload combined PR executables
uses: actions/upload-artifact@v4
with:
name: grove-pr-${{ needs.build-linux.outputs.pr_number }}-${{ needs.build-linux.outputs.version }}
path: ./executables
retention-days: 30
- name: Delete intermediate artifacts
uses: geekyeggo/delete-artifact@v5
with:
name: |
grove-linux-executables
grove-macos-executables
grove-windows-executable
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ needs.build-linux.outputs.pr_number }};
const version = '${{ needs.build-linux.outputs.version }}';
const runId = context.runId;
const body = `🌳 **Grove PR Build Ready!**
**Version:** \`${version}\`
**Install with:**
\`\`\`bash
curl https://i.safia.sh/captainsafia/grove/pr/${prNumber} | sh
\`\`\`
**Or if you already have grove installed:**
\`\`\`bash
grove self-update --pr ${prNumber}
\`\`\`
**Or download directly from [Actions Artifacts](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId})**
Available binaries:
- \`grove-linux-x64\`
- \`grove-linux-arm64\`
- \`grove-darwin-x64\`
- \`grove-darwin-arm64\`
- \`grove-windows-x64.exe\``;
// Check if a comment already exists
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Grove PR Build Ready')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: body,
});
}