diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..15e7df7 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,32 @@ +feature: + - changed-files: + - any-glob-to-any-file: ["**/*.go", "internal/**", "cmd/**"] + - head-branch: ["^feature/", "^feat/"] + +enhancement: + - head-branch: ["^enhancement/", "^enh/"] + +bugfix: + - head-branch: ["^bugfix/", "^fix/"] + +chore: + - changed-files: + - any-glob-to-any-file: [".github/**", "**/Dockerfile", "**/docker-compose*.yml"] + - head-branch: ["^chore/", "^deps/"] + +docs: + - changed-files: + - any-glob-to-any-file: ["**/*.md"] + +refactor: + - head-branch: ["^refactor/"] + +security: + - changed-files: + - any-glob-to-any-file: ["internal/**/crypto/**", "**/*auth*/*", "**/security/**"] + - head-branch: ["^security/"] + +tests: + - changed-files: + - any-glob-to-any-file: ["**/*_test.go", "test/**"] + - head-branch: ["^test/", "^tests/"] diff --git a/.github/labels.json b/.github/labels.json new file mode 100644 index 0000000..01db6cb --- /dev/null +++ b/.github/labels.json @@ -0,0 +1,10 @@ +[ + { "name": "feature", "color": "1f883d", "description": "New feature" }, + { "name": "enhancement", "color": "a2eeef", "description": "Enhancement to existing feature" }, + { "name": "bugfix", "color": "d73a4a", "description": "Bug fix" }, + { "name": "chore", "color": "8f5bff", "description": "Maintenance/devex" }, + { "name": "docs", "color": "0e8a16", "description": "Documentation" }, + { "name": "refactor", "color": "fbca04", "description": "Refactor" }, + { "name": "security", "color": "b60205", "description": "Security fix/hardening" }, + { "name": "tests", "color": "5319e7", "description": "Test changes" } +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..46dc2ee --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: go.sum + + - name: Verify dependencies + run: go mod verify + + - name: Build + run: CGO_ENABLED=0 go build ./... + + - name: Test + run: go test ./... + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: false diff --git a/.github/workflows/label-policy.yml b/.github/workflows/label-policy.yml new file mode 100644 index 0000000..1a2de72 --- /dev/null +++ b/.github/workflows/label-policy.yml @@ -0,0 +1,56 @@ +--- +name: Label Policy +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + label-sync: + name: Label Sync + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: EndBug/label-sync@v2 + with: + config-file: .github/labels.json + delete-other-labels: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + auto-label: + name: Auto Label + if: github.event_name == 'pull_request' + needs: [label-sync] + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 + with: + configuration-path: .github/labeler.yml + repo-token: ${{ secrets.GITHUB_TOKEN }} + + require-label: + name: Require Label + if: github.event_name == 'pull_request' + needs: [auto-label] + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + const required = ['feature','enhancement','bugfix','chore','docs','refactor','security','tests']; + const labels = await github.paginate( + github.rest.issues.listLabelsOnIssue, + { owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number } + ); + const present = labels.map(l => l.name); + const ok = required.some(l => present.includes(l)); + if (!ok) core.setFailed(`PR must include at least one of: ${required.join(', ')}`); + diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..9982f8f --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,36 @@ +--- +name: PR Title Check +on: + pull_request: + types: [opened, synchronize, reopened, edited] + +permissions: + pull-requests: read + +jobs: + pr-title: + name: PR Title Check + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feature + feat + enhancement + enh + bugfix + fix + chore + docs + doc + refactor + security + sec + tests + test + subjectPattern: "^[A-Z0-9].+" + subjectPatternError: "Start the subject with a capital letter." + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2686c93 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,121 @@ +name: Release + +on: + push: + tags: + - "v*" + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to ghcr.io + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version from tag + id: version + run: echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ghcr.io/kleffio/logs-loki:${{ steps.version.outputs.version }} + ghcr.io/kleffio/logs-loki:latest + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + + - name: Generate app token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.KLEFF_APP_ID }} + private-key: ${{ secrets.KLEFF_APP_PRIVATE_KEY }} + owner: kleffio + repositories: plugin-registry + + - name: Open PR to plugin-registry + uses: actions/github-script@v7 + with: + github-token: ${{ steps.app-token.outputs.token }} + script: | + const version = "${{ steps.version.outputs.version }}"; + const branch = `update/logs-loki-${version}`; + + const { data: file } = await github.rest.repos.getContent({ + owner: "kleffio", + repo: "plugin-registry", + path: "plugins.json", + }); + + const plugins = JSON.parse(Buffer.from(file.content, "base64").toString()); + const idx = plugins.findIndex(p => p.id === "loki-plugin"); + if (idx !== -1) plugins[idx].version = version; + + const { data: ref } = await github.rest.git.getRef({ + owner: "kleffio", + repo: "plugin-registry", + ref: "heads/main", + }); + + try { + await github.rest.git.createRef({ + owner: "kleffio", + repo: "plugin-registry", + ref: `refs/heads/${branch}`, + sha: ref.object.sha, + }); + } catch (e) { + if (e.status === 422) { + await github.rest.git.updateRef({ + owner: "kleffio", + repo: "plugin-registry", + ref: `heads/${branch}`, + sha: ref.object.sha, + force: true, + }); + } else throw e; + } + + await github.rest.repos.createOrUpdateFileContents({ + owner: "kleffio", + repo: "plugin-registry", + path: "plugins.json", + message: `chore: bump loki-plugin to v${version}`, + content: Buffer.from(JSON.stringify(plugins, null, 2) + "\n").toString("base64"), + branch, + sha: file.sha, + }); + + const { data: pr } = await github.rest.pulls.create({ + owner: "kleffio", + repo: "plugin-registry", + title: `chore: bump loki-plugin to v${version}`, + head: branch, + base: "main", + body: `Automated release PR from \`kleffio/loki-plugin\` tag \`v${version}\`.`, + }); + + await github.rest.pulls.merge({ + owner: "kleffio", + repo: "plugin-registry", + pull_number: pr.number, + merge_method: "squash", + }); diff --git a/Dockerfile b/Dockerfile index cec7763..a6a7574 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,11 @@ -# Build context is the plugins/ directory so we can access the local SDK. FROM golang:1.25-alpine AS builder WORKDIR /src -COPY plugin-sdk-go /plugin-sdk-go -COPY loki-plugin/go.mod loki-plugin/go.sum ./ +COPY go.mod go.sum ./ RUN go mod download -COPY loki-plugin/ . +COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /plugin ./cmd/plugin diff --git a/go.sum b/go.sum index c88ba27..4cbca5e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kleffio/plugin-sdk-go v0.1.8 h1:Nj4XXgnD51Gd1IlrYLPbfcjdK1rQHpoiObN27mrcgyI= +github.com/kleffio/plugin-sdk-go v0.1.8/go.mod h1:0QAnR0QpE5Onclbh/F55wi0XBlfiVZMGNTEui37LkF4= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=