Skip to content

Commit

Permalink
init version for gh action (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
fedordikarev authored Sep 26, 2024
1 parent 0efc00b commit 7135189
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 128 deletions.
47 changes: 39 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
# Set the base image to use for subsequent instructions
FROM alpine:3.20
ARG GO_VER=1.23.1
ARG DEBIAN_VER=bookworm

# Set the working directory inside the container
WORKDIR /usr/src
FROM golang:${GO_VER}-${DEBIAN_VER} AS go-build

ENV USER=gh-action
ENV UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
"${USER}"

WORKDIR /build

COPY go.mod go.sum ./
RUN go mod download

COPY cmd/gh-action/ ./

RUN go build -v -o ./gh-action-workflow-stats


FROM scratch

# Setup SSL certs
COPY --from=go-build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Setup user
COPY --from=go-build /etc/passwd /etc/group /etc/
USER gh-action:gh-action

# Copy the static executable
COPY --from=go-build /build/gh-action-workflow-stats /gh-action-workflow-stats

# Run the binary
ENTRYPOINT ["/gh-action-workflow-stats"]

# Copy any source file(s) required for the action
COPY entrypoint.sh .

# Configure the container to be run as an executable
ENTRYPOINT ["/usr/src/entrypoint.sh"]
115 changes: 7 additions & 108 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,111 +1,10 @@
# Hello, World! Docker Action

[![GitHub Super-Linter](https://github.com/actions/hello-world-docker-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter)
![CI](https://github.com/actions/hello-world-docker-action/actions/workflows/ci.yml/badge.svg)

This action prints `Hello, World!` or `Hello, <who-to-greet>!` to the log. To
learn how this action was built, see
[Creating a Docker container action](https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action).

## Create Your Own Action

To create your own action, you can use this repository as a template! Just
follow the below instructions:

1. Click the **Use this template** button at the top of the repository
1. Select **Create a new repository**
1. Select an owner and name for your new repository
1. Click **Create repository**
1. Clone your new repository

> [!CAUTION]
>
> Make sure to remove or update the [`CODEOWNERS`](./CODEOWNERS) file! For
> details on how to use this file, see
> [About code owners](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners).
## Usage

Here's an example of how to use this action in a workflow file:

```yaml
name: Example Workflow

on:
workflow_dispatch:
inputs:
who-to-greet:
description: Who to greet in the log
required: true
default: 'World'
type: string

jobs:
say-hello:
name: Say Hello
runs-on: ubuntu-latest

steps:
# Change @main to a specific commit SHA or version tag, e.g.:
# actions/hello-world-docker-action@e76147da8e5c81eaf017dede5645551d4b94427b
# actions/[email protected]
- name: Print to Log
id: print-to-log
uses: actions/hello-world-docker-action@main
with:
who-to-greet: ${{ inputs.who-to-greet }}
```
For example workflow runs, check out the
[Actions tab](https://github.com/actions/hello-world-docker-action/actions)!
:rocket:
# Github Workflow Stats exporter to Postgres

## Inputs

| Input | Default | Description |
| -------------- | ------- | ------------------------------- |
| `who-to-greet` | `World` | The name of the person to greet |

## Outputs

| Output | Description |
| ------ | ----------------------- |
| `time` | The time we greeted you |

## Test Locally

After you've cloned the repository to your local machine or codespace, you'll
need to perform some initial setup steps before you can test your action.

> [!NOTE]
>
> You'll need to have a reasonably modern version of
> [Docker](https://www.docker.com/get-started/) handy (e.g. docker engine
> version 20 or later).

1. :hammer_and_wrench: Build the container

Make sure to replace `actions/hello-world-docker-action` with an appropriate
label for your container.

```bash
docker build -t actions/hello-world-docker-action .
```

1. :white_check_mark: Test the container

You can pass individual environment variables using the `--env` or `-e` flag.

```bash
$ docker run --env INPUT_WHO_TO_GREET="Mona Lisa Octocat" actions/hello-world-docker-action
::notice file=entrypoint.sh,line=7::Hello, Mona Lisa Octocat!
```

Or you can pass a file with environment variables using `--env-file`.

```bash
$ echo "INPUT_WHO_TO_GREET=\"Mona Lisa Octocat\"" > ./.env.test
$ docker run --env-file ./.env.test actions/hello-world-docker-action
::notice file=entrypoint.sh,line=7::Hello, Mona Lisa Octocat!
```
| Input | Description |
| ------------------- | -------------------------------------- |
| `DB_URI` | Database URI |
| `DB_TABLE` | Table for storing Workflow stats |
| `GH_RUN_ID` | Workflow Run Id to get information on |
| `GH_TOKEN` | Github Token, optional for public Repo |
12 changes: 12 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,21 @@ inputs:
db_uri:
description: Postgres DB URI
required: true
db_table:
description: Table name to store Workflow stats
required: true
gh_run_id:
description: Workflow Run Id to get information on
required: true
gh_token:
description: Github Token with permissions to access Workflows. Not required for public repos.
required: false

runs:
using: docker
image: "docker://yatheo/gh-workflow-stats-action:latest"
env:
DB_URI: ${{ inputs.db_uri }}
DB_TABLE: ${{ inputs.db_table }}
GH_RUN_ID: ${{ inputs.gh_run_id }}
GH_TOKEN: ${{ inputs.gh_token }}
56 changes: 56 additions & 0 deletions cmd/gh-action/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import (
"fmt"
"os"
"strings"
)

type configType struct {
dbUri string
dbTable string
runID string
repository string
owner string
repo string
githubToken string
}

func getConfig() (configType, error) {
dbUri := os.Getenv("DB_URI")
if len(dbUri) == 0 {
return configType{}, fmt.Errorf("missing env: DB_URI")
}

dbTable := os.Getenv(("DB_TABLE"))
if len(dbTable) == 0 {
return configType{}, fmt.Errorf("missing env: DB_TABLE")
}

repository := os.Getenv("GITHUB_REPOSITORY")
if len(repository) == 0 {
return configType{}, fmt.Errorf("missing env: GITHUB_REPOSITORY")
}

runID := os.Getenv("GH_RUN_ID")
if len(runID) == 0 {
return configType{}, fmt.Errorf("missing env: GH_RUN_ID")
}

githubToken := os.Getenv("GH_TOKEN")

repoDetails := strings.Split(repository, "/")
if len(repoDetails) != 2 {
return configType{}, fmt.Errorf("invalid env: GITHUB_REPOSITORY")
}

return configType{
dbUri: dbUri,
dbTable: dbTable,
runID: runID,
repository: repository,
owner: repoDetails[0],
repo: repoDetails[1],
githubToken: githubToken,
}, nil
}
18 changes: 18 additions & 0 deletions cmd/gh-action/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"time"
)

type WorkflowStat struct {
WorkflowId int64
Name string
Status string
Conclusion string
RunId int
RunAttempt int
StartedAt time.Time
UpdatedAt time.Time
RepoName string
Event string
}
58 changes: 58 additions & 0 deletions cmd/gh-action/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"fmt"

"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)

var (
scheme = `
CREATE TABLE %s (
workflowid BIGINT,
name TEXT,
status TEXT,
conclusion TEXT,
runid INT,
runattempt INT,
startedat TIMESTAMP,
updatedat TIMESTAMP,
reponame TEXT,
event TEXT,
PRIMARY KEY(workflowid, runattempt)
)
`
)

func initDatabase(conf configType) error {
db, err := sqlx.Connect("postgres", conf.dbUri)
if err != nil {
return err
}

_, err = db.Exec(fmt.Sprintf(scheme, conf.dbTable))
if err != nil {
return err
}
return nil
}

func saveRecords(conf configType, records *WorkflowStat) error {
db, err := sqlx.Connect("postgres", conf.dbUri)
if err != nil {
return err
}

query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", conf.dbTable,
"workflowid, name, status, conclusion, runid, runattempt, startedAt, updatedAt, repoName, event",
":workflowid, :name, :status, :conclusion, :runid, :runattempt, :startedat, :updatedat, :reponame, :event",
)

_, err = db.NamedExec(query, *records)

if err != nil {
return err
}
return nil
}
51 changes: 51 additions & 0 deletions cmd/gh-action/gh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"context"
"fmt"
"net/http"
"strconv"

"github.com/google/go-github/v65/github"
"golang.org/x/oauth2"
)

func createRecords(ctx context.Context, conf configType) (*WorkflowStat, error) {
var token *http.Client
if len(conf.githubToken) != 0 {
token = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: conf.githubToken},
))
}

client := github.NewClient(token)

runID, err := strconv.ParseInt(conf.runID, 10, 64)
if err != nil {
return nil, err
}

fmt.Printf("Getting data for %s/%s, runId %d\n", conf.owner, conf.repo, runID)
workflowData, _, err := client.Actions.GetWorkflowRunByID(ctx, conf.owner, conf.repo, runID)
if err != nil {
return nil, err
}

if workflowData == nil {
fmt.Printf("Got nil\n")
return &WorkflowStat{RepoName: conf.repository}, nil
}

return &WorkflowStat{
WorkflowId: *workflowData.ID,
Name: *workflowData.Name,
Status: *workflowData.Status,
Conclusion: *workflowData.Conclusion,
RunId: *workflowData.RunNumber,
RunAttempt: *workflowData.RunAttempt,
StartedAt: workflowData.CreatedAt.Time,
UpdatedAt: workflowData.UpdatedAt.Time,
RepoName: *workflowData.Repository.FullName,
Event: *workflowData.Event,
}, nil
}
Loading

0 comments on commit 7135189

Please sign in to comment.