diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0..301daf1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,5 @@ blank_issues_enabled: false +contact_links: + - name: Question or Support + url: https://github.com/tale/headplane/discussions/new?category=q-a + about: Ask questions or get help with your setup diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..dbfbe38 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,45 @@ +Agent: + - changed-files: + - any-glob-to-any-file: + - cmd/hp_agent/** + - internal/** + - go.mod + - go.sum + +UI/UX: + - changed-files: + - any-glob-to-any-file: + - app/components/** + - app/layouts/** + - app/root.tsx + - app/tailwind.css + +Authentication: + - changed-files: + - any-glob-to-any-file: + - app/server/web/** + - app/routes/auth*/** + +Config: + - changed-files: + - any-glob-to-any-file: + - app/server/config/** + - internal/config/** + - config.example.yaml + +Integrations: + - changed-files: + - any-glob-to-any-file: + - app/server/headscale/** + - app/openapi-*.json + +Web SSH: + - changed-files: + - any-glob-to-any-file: + - cmd/hp_ssh/** + +Docs: + - changed-files: + - any-glob-to-any-file: + - docs/** + - README.md diff --git a/.github/workflows/automated.yaml b/.github/workflows/automated.yaml index 5fcab1a..110aedb 100644 --- a/.github/workflows/automated.yaml +++ b/.github/workflows/automated.yaml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Nix uses: DeterminateSystems/nix-installer-action@main diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 981afc7..f1f11a9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -56,7 +56,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Nix uses: DeterminateSystems/nix-installer-action@main diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml new file mode 100644 index 0000000..155f4da --- /dev/null +++ b/.github/workflows/labeler.yaml @@ -0,0 +1,17 @@ +name: Labeler +on: + pull_request_target: + types: [opened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + name: Label PR + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v6 + with: + sync-labels: true diff --git a/.github/workflows/lifecycle.yaml b/.github/workflows/lifecycle.yaml new file mode 100644 index 0000000..a31e66d --- /dev/null +++ b/.github/workflows/lifecycle.yaml @@ -0,0 +1,87 @@ +name: Release Lifecycle +on: + push: + tags: + - "v*" + +permissions: + issues: write + +jobs: + beta: + name: Beta Release + if: contains(github.ref_name, '-') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Label and comment on referenced issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG="${GITHUB_REF_NAME}" + PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + + if [ -z "$PREV_TAG" ]; then + echo "No previous tag found, skipping" + exit 0 + fi + + echo "Processing issues referenced between ${PREV_TAG} and ${TAG}" + ISSUES=$(git log --format="%B" "${PREV_TAG}..HEAD" | grep -oE '#[0-9]+' | sort -u | tr -d '#') + + for ISSUE in $ISSUES; do + [ -z "$ISSUE" ] && continue + + STATE=$(gh issue view "$ISSUE" --json state --jq '.state' \ + --repo "${{ github.repository }}" 2>/dev/null || echo "") + [ "$STATE" != "OPEN" ] && continue + + echo "Labeling and commenting on #${ISSUE}" + gh issue edit "$ISSUE" --add-label "In Beta" \ + --repo "${{ github.repository }}" 2>/dev/null || true + gh issue comment "$ISSUE" \ + --body "🧪 Available in [\`${TAG}\`](https://github.com/${{ github.repository }}/releases/tag/${TAG})" \ + --repo "${{ github.repository }}" 2>/dev/null || true + done + + stable: + name: Stable Release + if: ${{ !contains(github.ref_name, '-') }} + runs-on: ubuntu-latest + steps: + - name: Close milestone issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG="${GITHUB_REF_NAME}" + VERSION="${TAG#v}" + + MILESTONE_NUMBER=$(gh api "repos/${{ github.repository }}/milestones" \ + --jq ".[] | select(.title == \"${VERSION}\") | .number" 2>/dev/null || echo "") + + if [ -z "$MILESTONE_NUMBER" ]; then + echo "No milestone found for ${VERSION}, skipping" + exit 0 + fi + + echo "Processing milestone ${VERSION} (#${MILESTONE_NUMBER})" + gh api "repos/${{ github.repository }}/issues?milestone=${MILESTONE_NUMBER}&state=open&per_page=100" \ + --paginate --jq '.[].number' 2>/dev/null | while IFS= read -r ISSUE; do + [ -z "$ISSUE" ] && continue + + echo "Closing #${ISSUE}" + gh issue edit "$ISSUE" --remove-label "In Beta" \ + --repo "${{ github.repository }}" 2>/dev/null || true + gh issue comment "$ISSUE" \ + --body "✅ Released in [\`${TAG}\`](https://github.com/${{ github.repository }}/releases/tag/${TAG})" \ + --repo "${{ github.repository }}" 2>/dev/null || true + gh issue close "$ISSUE" \ + --repo "${{ github.repository }}" 2>/dev/null || true + done + + echo "Closing milestone ${VERSION}" + gh api -X PATCH "repos/${{ github.repository }}/milestones/${MILESTONE_NUMBER}" \ + -f state=closed 2>/dev/null || true diff --git a/.github/workflows/next.yaml b/.github/workflows/next.yaml deleted file mode 100644 index ee63087..0000000 --- a/.github/workflows/next.yaml +++ /dev/null @@ -1,82 +0,0 @@ -name: Pre-release (next) -on: - workflow_dispatch: - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: pre-release-${{ github.ref }} - cancel-in-progress: true - -permissions: - actions: write # Allow canceling in-progress runs - contents: read # Read access to the repository - packages: write # Write access to the container registry - id-token: write # For the attest action to push - attestations: write # For the attest action to push - -jobs: - publish: - # Ensure the action only runs if manually dispatched or a PR on the `next` branch in the *main* repository is opened or synchronized. - if: ${{ github.event_name == 'workflow_dispatch' || (github.event.pull_request && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.ref == 'next') }} - name: Docker Pre-release - runs-on: ubuntu-latest - strategy: - matrix: - include: - - target: final - tag: "next" - - target: debug-shell - tag: "next-shell" - - steps: - - name: Check out the repo - uses: actions/checkout@v4 - - - name: Docker Metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=${{ matrix.tag }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to ghcr.io - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and publish ghcr.io/${{ github.repository }}:${{ matrix.tag }} - uses: docker/build-push-action@v6 - id: push - with: - context: . - file: ./Dockerfile - target: ${{ matrix.target }} - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64, linux/arm64 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - IMAGE_TAG=ghcr.io/${{ github.repository }}:${{ matrix.tag }} - HEADPLANE_VERSION=next+${{ github.sha }} - secrets: | - gh_token=${{ secrets.GITHUB_TOKEN }} - - - name: Attestation Provenance for ghcr.io/${{ github.repository }}:${{ matrix.tag }} - uses: actions/attest-build-provenance@v2 - id: attest - with: - subject-name: ghcr.io/${{ github.repository }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6517064..6572118 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,7 +29,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Docker Metadata id: meta diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 0000000..30a1666 --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,29 @@ +name: Stale +on: + schedule: + - cron: "30 1 * * *" + workflow_dispatch: + +permissions: + actions: write + issues: write + +jobs: + stale: + name: Close stale issues + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v10 + with: + stale-issue-label: Stale + only-labels: "Needs Info" + days-before-stale: 30 + stale-issue-message: > + This issue has been waiting for information for 30 days. + It will be closed in 7 days if there is no further activity. + Feel free to reopen if you can provide the requested details. + close-issue-message: > + Closed due to inactivity. Feel free to reopen with the + requested information. + days-before-pr-stale: -1 + days-before-pr-close: -1 diff --git a/.github/workflows/triage.yaml b/.github/workflows/triage.yaml new file mode 100644 index 0000000..5b52e6f --- /dev/null +++ b/.github/workflows/triage.yaml @@ -0,0 +1,20 @@ +name: Triage +on: + issues: + types: [milestoned] + +permissions: + issues: write + +jobs: + remove-triage: + name: Remove Needs Triage + runs-on: ubuntu-latest + steps: + - name: Remove Needs Triage label + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh issue edit ${{ github.event.issue.number }} \ + --remove-label "Needs Triage" \ + --repo ${{ github.repository }} 2>/dev/null || true