Skip to content

Commit

Permalink
Initial version (#1)
Browse files Browse the repository at this point in the history
* initial action scaffold

* add mock templates for testing

* add basic deno entry point

* update action boilerplate with cpu and arch checks

* add workflow for testing the Action

* update for cleaner exits

* move env variable checks inside the main function

* set correct permissions

* update CI to point to demo temporarily

* actually simplify the main script since it's a script anyway

* move "api helpers" into a separate file for readability

* check against API for existing templates and fork the entries into separate lists for creating and updating

* upd templates

* rename templates

* Point deno to main.ts in the action path not just in the current
directory

* remove comment

* add README

* add badge

* Apply suggestions from code review

Co-authored-by: Mari <me@cutegirl.tech>

* Apply suggestions from code review

Co-authored-by: Benno van den Berg <hatchan@users.noreply.github.com>

* short circuit the action if shasums don't match

* update CI

* update README

---------

Co-authored-by: Mari <me@cutegirl.tech>
Co-authored-by: Benno van den Berg <hatchan@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 7, 2024
1 parent 9990849 commit e35786a
Show file tree
Hide file tree
Showing 11 changed files with 474 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .fiberplane/templates/p1.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// For documentation on Fiberplane Templates, see: https://docs.fiberplane.com/templates
local fp = import 'fiberplane.libsonnet';
local c = fp.cell;
local fmt = fp.format;

function(
title='WE GOT P1 PPL'
)
fp.notebook
.new(title)
.setTimeRangeRelative(minutes=60)
.addLabels({})
.addCells([
c.h1('This is a section'),
c.text('You can add any types of cells and pre-fill content'),
])

17 changes: 17 additions & 0 deletions .fiberplane/templates/p2.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// For documentation on Fiberplane Templates, see: https://docs.fiberplane.com/templates
local fp = import 'fiberplane.libsonnet';
local c = fp.cell;
local fmt = fp.format;

function(
title='AAAND IT P2'
)
fp.notebook
.new(title)
.setTimeRangeRelative(minutes=60)
.addLabels({})
.addCells([
c.h1('This is a section'),
c.text('You can add any types of cells and pre-fill content'),
])

1 change: 1 addition & 0 deletions .fiberplane/templates/random_json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
17 changes: 17 additions & 0 deletions .fiberplane/templates/template3.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// For documentation on Fiberplane Templates, see: https://docs.fiberplane.com/templates
local fp = import 'fiberplane.libsonnet';
local c = fp.cell;
local fmt = fp.format;

function(
title='TEST 3'
)
fp.notebook
.new(title)
.setTimeRangeRelative(minutes=60)
.addLabels({})
.addCells([
c.h1('This is a section'),
c.text('You can add any types of cells and pre-fill content'),
])

22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Test the GitHub Action

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:

- uses: actions/checkout@v4

- name: Integration test
uses: ./ # fiberplane/sync-templates@v1
id: integration-test-1
with:
api-token: ${{ secrets.FP_TOKEN }}
workspace-id: wTTZcPV5Q8qqQ-340fAEWQ

28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
# sync-templates

[![Continuous Integration](https://github.com/fiberplane/sync-templates/actions/workflows/ci.yml/badge.svg)](https://github.com/fiberplane/sync-templates/actions/workflows/ci.yml)

The `fiberplane/sync-templates` action is a utility that syncs your Fiberplane Templates from a designated directory in your repository with your Fiberplane Workspace.

## Usage
This action can be run on `ubuntu-latest` and `macos-latest` GitHub Actions runners.

A minimum working example of the action:
```yaml
steps:
- uses: fiberplane/sync-templates@v1
with:
api-token: ${{ secrets.FP_TOKEN }} # it is best practice to keep your secrets in GitHub Secrets
workspace-id: <your_workspace_id> # you can look it up with: fp workspaces list
```
The `sync-templates` action accepts the following inputs:
- `api-token` (**required**) - the Fiberplane API token used to access the workspace
- `workspace-id` (**required**) - the ID of the workspace where the Templates should be sync'ed to
- `templates-directory` (optional) - directory where valid Templates `*.jsonnet` files are located, default: `.fiberplane/templates/`
- `fp-version` (optional) - explicit version of the `fp` CLI that should be used in the action, default: `latest`
- `fp-base-url`(optional) - the base URL of the Fiberplane API, default `studio.fiberplane.com`

When run the action will:
1. Download, setup, and cache the Deno runtime and the Fiberplane CLI (`fp`).
2. Validate that the intended Templates are syntactically correct.
3. Create and/or upload the intended Templates to a Fiberplane Workspace
99 changes: 99 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Sync Templates
description: Synchronizes Templates between your repository and Fiberplane
branding:
icon: tag
color: gray-dark

inputs:
api-token:
description: API token used to access the Fiberplane API with
required: true
workspace-id:
description: ID of the workspace to which the templates should be uploaded to
required: true
fp-base-url:
description: Base URL of the Fiberplane API
default: https://studio.fiberplane.com
templates-directory:
description: "Custom directory that should be monitored for Template JSONNET files (default: .fiberplane/templates/)"
default: .fiberplane/templates/
fp-version:
description: Version of the Fiberplane CLI to use (latest by default)
default: latest

runs:
using: composite
steps:

- uses: denoland/setup-deno@v1
with:
deno-version: v1.x

- name: Set up Fiberplane CLI
shell: bash
id: download
env:
FP_VERSION: ${{ inputs.fp-version }}
run: |
echo "== Setting up Fiberplane CLI =="
echo "Running on ${{ runner.arch }}"
if [ ${{ runner.arch }} = "ARM64" ]; then
FP_ARCH="aarch64"
elif [ ${{ runner.arch }} = "X86" ] || [ ${{ runner.arch }} = "X64" ]; then
FP_ARCH="x86_64"
else
echo "Fiberplane CLI supports only x86_64 and ARM64 CPU architectures"
exit 1
fi
echo "Running on ${{ runner.os }}"
if [ ${{ runner.os }} = "Linux" ]; then
FP_OS="unknown-linux-gnu"
elif [ ${{ runner.os }} = "macOS" ]; then
FP_OS="apple-darwin"
else
echo "Fiberplane CLI supports only Linux and macOS"
exit 1
fi
if [ "$FP_VERSION" != "latest" ]; then
FP_VERSION="v${FP_VERSION}"
fi
echo "Going to install: $FP_VERSION version of fp"
URL="https://fp.dev/fp/${FP_VERSION}/${FP_ARCH}-${FP_OS}"
EXPECTED_SHA256SUM="$(curl -H user-agent:fiberplane-github-action -s -L "${URL}/checksum.sha256" | grep fp | awk '{print $1;}')"
curl -H user-agent:fiberplane-github-action -L "${URL}/fp" -o fp
ACTUAL_SHA256SUM=$(sha256sum fp | awk '{print $1;}')
echo "Expected sha256: $EXPECTED_SHA256SUM"
echo "Actual sha256: $ACTUAL_SHA256SUM"
if [ "$ACTUAL_SHA256SUM" != "$EXPECTED_SHA256SUM" ]; then
exit 1
fi
chmod +x fp
sudo mv fp /usr/local/bin
- name: Run template validate and sync
shell: bash
env:
API_TOKEN: ${{ inputs.api-token }}
WORKSPACE_ID: ${{ inputs.workspace-id }}
FP_BASE_URL: ${{ inputs.fp-base-url }}
TEMPLATES_DIRECTORY: ${{ inputs.templates-directory }}
run: |
deno run \
--allow-read \
--allow-env \
--allow-run=/usr/local/bin/fp \
--allow-net=${{ inputs.fp-base-url }} \
${{ github.action_path }}/main.ts
157 changes: 157 additions & 0 deletions api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// functions for interacting with the fp-cli, should be replaced with a proper
// API client when we get around to it

const FP = "/usr/local/bin/fp";
const decoder = new TextDecoder();

type Template = {
id: string;
name: string;
description: string;
created_at: string;
updated_at: string;
};

export async function createTemplate(
templateFile: string,
templatesDirectory: string,
apiToken: string,
workspaceId: string,
fpBaseUrl: string,
) {
console.log(`Creating template ${templatesDirectory + templateFile}`);

const command = new Deno.Command(FP, {
cwd: templatesDirectory,
args: [
"templates",
"create",
templateFile,
"--template-name",
templateFile.replace(".jsonnet", ""),
"--description",
templateFile.replace(".jsonnet", ""),
"--create-trigger",
"false",
],
clearEnv: true,
env: {
FP_TOKEN: apiToken,
API_BASE: fpBaseUrl,
WORKSPACE_ID: workspaceId,
},
});

const { code, stdout: stdoutBuf, stderr: stderrBuf } = await command.output();

const stderr = decoder.decode(stderrBuf);
const stdout = decoder.decode(stdoutBuf);

if (code !== 0) {
console.log(stdout + stderr);
throw new Error(stderr);
}

console.log(stdout + stderr);
}

export async function listTemplates(
apiToken: string,
workspaceId: string,
fpBaseUrl: string,
): Promise<Template[]> {
const command = new Deno.Command(FP, {
args: ["templates", "list", "--output", "json"],
clearEnv: true,
env: {
FP_TOKEN: apiToken,
API_BASE: fpBaseUrl,
WORKSPACE_ID: workspaceId,
},
});

const { code, stdout: stdoutBuf, stderr: stderrBuf } = await command.output();

const stderr = decoder.decode(stderrBuf);
const stdout = decoder.decode(stdoutBuf);

if (code !== 0) {
console.log(stdout + stderr);
throw new Error(stderr);
}

let out;

try {
out = JSON.parse(stdout);
} catch (err) {
console.log(stdout + stderr);
throw new Error(err);
}

return out;
}

export async function updateTemplate(
templateFile: string,
templatesDirectory: string,
apiToken: string,
workspaceId: string,
fpBaseUrl: string,
) {
console.log(`Updating template ${templatesDirectory + templateFile}`);

const command = new Deno.Command(FP, {
cwd: templatesDirectory,
args: [
"templates",
"update",
templateFile.replace(".jsonnet", ""),
"--template-path",
templateFile,
],
clearEnv: true,
env: {
FP_TOKEN: apiToken,
API_BASE: fpBaseUrl,
WORKSPACE_ID: workspaceId,
},
});

const { code, stdout: stdoutBuf, stderr: stderrBuf } = await command.output();

const stderr = decoder.decode(stderrBuf);
const stdout = decoder.decode(stdoutBuf);

if (code !== 0) {
console.log(stdout + stderr);
throw new Error(stderr);
}

console.log(stdout + stderr);
}

export async function validateTemplate(
templateFile: string,
templatesDirectory: string,
) {
console.log(`Validating template ${templatesDirectory + templateFile}`);

const command = new Deno.Command(FP, {
cwd: templatesDirectory,
args: ["templates", "validate", templateFile],
clearEnv: true,
});

const { code, stdout: stdoutBuf, stderr: stderrBuf } = await command.output();

const stderr = decoder.decode(stderrBuf);
const stdout = decoder.decode(stdoutBuf);

if (code !== 0) {
console.log(stdout + stderr);
throw new Error(stderr);
}

console.log(stdout + stderr);
}
1 change: 1 addition & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
7 changes: 7 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e35786a

Please sign in to comment.