diff --git a/.github/workflows/conformance.yaml b/.github/workflows/conformance.yaml deleted file mode 100644 index fbd1ce18..00000000 --- a/.github/workflows/conformance.yaml +++ /dev/null @@ -1,63 +0,0 @@ -name: Java Conformance CI -on: - push: - branches: - - master - pull_request: -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - java: [ - 11.x - # 12.x, - # 13.x - ] - steps: - - uses: actions/checkout@v2 - - - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v1 - with: - java-version: ${{ matrix.java }} - - - name: Setup Go - uses: actions/setup-go@v2 - with: - go-version: '1.15' - - - name: Build API with Maven - run: (cd functions-framework-api/ && mvn install) - - - name: Build invoker with Maven - run: (cd invoker/ && mvn install) - - - name: Run HTTP conformance tests - uses: GoogleCloudPlatform/functions-framework-conformance/action@v1.2.1 - with: - version: 'v1.2.1' - functionType: 'http' - useBuildpacks: false - cmd: "'mvn -f invoker/conformance/pom.xml function:run -Drun.functionTarget=com.google.cloud.functions.conformance.HttpConformanceFunction'" - startDelay: 10 - - - name: Run background event conformance tests - uses: GoogleCloudPlatform/functions-framework-conformance/action@v1.2.1 - with: - version: 'v1.2.1' - functionType: 'legacyevent' - useBuildpacks: false - validateMapping: true - cmd: "'mvn -f invoker/conformance/pom.xml function:run -Drun.functionTarget=com.google.cloud.functions.conformance.BackgroundEventConformanceFunction'" - startDelay: 10 - - - name: Run cloudevent conformance tests - uses: GoogleCloudPlatform/functions-framework-conformance/action@v1.2.1 - with: - version: 'v1.2.1' - functionType: 'cloudevent' - useBuildpacks: false - validateMapping: true - cmd: "'mvn -f invoker/conformance/pom.xml function:run -Drun.functionTarget=com.google.cloud.functions.conformance.CloudEventsConformanceFunction'" - startDelay: 10 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml deleted file mode 100644 index 82a20cfe..00000000 --- a/.github/workflows/lint.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: Java Lint CI -on: - push: - branches: - - master - pull_request: - workflow_dispatch: -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK - uses: actions/setup-java@v1 - with: - java-version: 11.x - - name: Build API with Maven - run: (cd functions-framework-api/ && mvn install) - - name: Lint Functions Framework API - run: (cd functions-framework-api/ && mvn clean verify -DskipTests -P lint) - - name: Build Invoker with Maven - run: (cd functions-framework-api/ && mvn install) - - name: Lint Invoker - run: (cd invoker/ && mvn clean verify -DskipTests -P lint) - formatting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 # v2 minimum required - - name: Run formatter - id: formatter - uses: axel-op/googlejavaformat-action@v3 - with: - args: "--dry-run --set-exit-if-changed" - continue-on-error: true - - name: Check for failure - if: steps.formatter.outcome != 'success' - run: | - echo "Java format check failed, see 'Run formatter' step for more information." - echo "See https://github.com/google/google-java-format for options on running the formatter locally." - exit 1 \ No newline at end of file diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..9686c419 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,43 @@ +name: Maven Publish +on: + push: + branches: + - 'main' + tags: + - '*' + paths: + - '.github/workflows/**' + - 'functions-framework-api/pom.xml' + - 'functions-framework-api/src/**' + - 'functions-framework-invoker/pom.xml' + - 'functions-framework-invoker/src/main/**' + +jobs: + publish: + runs-on: ubuntu-18.04 + steps: + - name: Check out Git repository + uses: actions/checkout@v3 + + - name: Install Java and Maven + uses: actions/setup-java@v1 + with: + java-version: 11 + + - name: Publish framework API + uses: samuelmeuli/action-maven-publish@v1 + with: + directory: functions-framework-api + gpg_private_key: ${{ secrets.GPG_KEY }} + gpg_passphrase: ${{ secrets.GPG_PASSWORD }} + nexus_username: ${{ secrets.OSSRH_USER }} + nexus_password: ${{ secrets.OSSRH_PASSWORD }} + + - name: Publish framework invoker + uses: samuelmeuli/action-maven-publish@v1 + with: + directory: functions-framework-invoker + gpg_private_key: ${{ secrets.GPG_KEY }} + gpg_passphrase: ${{ secrets.GPG_PASSWORD }} + nexus_username: ${{ secrets.OSSRH_USER }} + nexus_password: ${{ secrets.OSSRH_PASSWORD }} diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml deleted file mode 100644 index 1938fc01..00000000 --- a/.github/workflows/unit.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Java Unit CI -on: - push: - branches: - - master - pull_request: -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - java: [ - 11.x, - 17.x - ] - steps: - - uses: actions/checkout@v2 - - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v2 - with: - java-version: ${{ matrix.java }} - distribution: temurin - - name: Build with Maven - run: (cd functions-framework-api/ && mvn install) - - name: Test - run: (cd invoker/ && mvn test) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f7e4114c..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,82 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution; -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. - -## Community Guidelines - -This project follows [Google's Open Source Community -Guidelines](https://opensource.google.com/conduct/). - -## Developing - -This project is divided into multiple packages, primarily: - -- [`functions-framework-api`](./functions-framework-api) – The interfaces for functions. -- [`java-function-invoker`](./invoker) - - `core` - The function invoker - - `testfunction` - A set of test functions - - `function-maven-plugin` - The Maven plugin for building functions - - `conformance` - A set of functions used for conformance testing - -### Setup JDK 11 / 17 - -Install JDK 11 and 17. One way to install these is through [SDK man](https://sdkman.io/). - -```sh -sdk install java 11.0.2-open -sdk install java 17-open -sdk use java 17-open -sdk use java 11.0.2-open -``` - -Verify Java version with: - -```sh -java --version -``` - -### Setup Apache Maven - -Install `mvn`: - -https://maven.apache.org/install.html - -### Formatting -This repo follows the Google Java Style guide for formatting. You can setup the -formatting tool locally using one of the options provided at -[google/google-java-format](https://github.com/google/google-java-format#google-java-format). - -## Install and Run Invoker Tests Locally - -``` -cd invoker; -mvn test; -``` - -### Running Conformance Tests Locally - -First, install Go 1.16+, then run the conformance tests with this script: - -``` -./run_conformance_tests.sh -``` diff --git a/README.md b/README.md index 67fa315f..cbda9fc2 100644 --- a/README.md +++ b/README.md @@ -1,319 +1,3 @@ # Functions Framework for Java -[![Maven Central (functions-framework-api)](https://img.shields.io/maven-central/v/com.google.cloud.functions/functions-framework-api.svg?label=functions-framework-api)](https://search.maven.org/artifact/com.google.cloud.functions/functions-framework-api) -[![Maven Central (java-function-invoker)](https://img.shields.io/maven-central/v/com.google.cloud.functions.invoker/java-function-invoker.svg?label=java-function-invoker)](https://search.maven.org/artifact/com.google.cloud.functions.invoker/java-function-invoker) -[![Maven Central (function-maven-plugin)](https://img.shields.io/maven-central/v/com.google.cloud.functions/function-maven-plugin.svg?label=function-maven-plugin)](https://search.maven.org/artifact/com.google.cloud.functions/function-maven-plugin) - -[![Java Unit CI](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/unit.yaml/badge.svg)](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/unit.yaml) -[![Java Lint CI](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/lint.yaml/badge.svg)](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/lint.yaml) -[![Java Conformance CI](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/conformance.yaml/badge.svg)](https://github.com/GoogleCloudPlatform/functions-framework-java/actions/workflows/conformance.yaml) - -An open source FaaS (Function as a service) framework for writing portable -Java functions -- brought to you by the Google Cloud Functions team. - -The Functions Framework lets you write lightweight functions that run in many -different environments, including: - -* [Google Cloud Functions](https://cloud.google.com/functions/) -* Your local development machine -* [Cloud Run](https://cloud.google.com/run/) and [Cloud Run for Anthos](https://cloud.google.com/anthos/run/) -* [Knative](https://github.com/knative/)-based environments - -## Installation - -The Functions Framework for Java uses -[Java](https://java.com/en/download/help/download_options.xml) and -[Maven](http://maven.apache.org/install.html) (the `mvn` command), -for building and deploying functions from source. - -However, it is also possible to build your functions using -[Gradle](https://gradle.org/), as JAR archives, that you will deploy with the -`gcloud` command-line. - -## Quickstart: Hello, World on your local machine - -A function is typically structured as a Maven project. We recommend using an IDE -that supports Maven to create the Maven project. Add this dependency in the -`pom.xml` file of your project: - -```xml - - com.google.cloud.functions - functions-framework-api - 1.0.4 - provided - -``` - -If you are using Gradle to build your functions, you can define the Functions -Framework dependency in your `build.gradle` project file as follows: - -```groovy - dependencies { - implementation 'com.google.cloud.functions:functions-framework-api:1.0.4' - } - -``` - -### Writing an HTTP function - -Create a file `src/main/java/com/example/HelloWorld.java` with the following -contents: - -```java -package com.example; - -import HttpFunction; -import HttpRequest; -import HttpResponse; - -public class HelloWorld implements HttpFunction { - @Override - public void service(HttpRequest request, HttpResponse response) - throws Exception { - response.getWriter().write("Hello, World\n"); - } -} -``` - - -## Quickstart: Create a Background Function - -There are two ways to write a Background function, which differ in how the -payload of the incoming event is represented. In a "raw" background function -this payload is presented as a JSON-encoded Java string. In a "typed" background -function the Functions Framework deserializes the JSON payload into a Plain Old -Java Object (POJO). - -### Writing a Raw Background Function - -Create a file `src/main/java/com/example/Background.java` with the following -contents: - -```java -package com.example; - -import Context; -import RawBackgroundFunction; -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import java.util.logging.Logger; - -public class Background implements RawBackgroundFunction { - private static final Logger logger = - Logger.getLogger(Background.class.getName()); - - @Override - public void accept(String json, Context context) { - Gson gson = new Gson(); - JsonObject jsonObject = gson.fromJson(json, JsonObject.class); - logger.info("Received JSON object: " + jsonObject); - } -} -``` - -### Writing a Typed Background Function - -Create a file `src/main/java/com/example/PubSubBackground` with the following -contents: - -```java -package com.example; - -import BackgroundFunction; -import Context; -import java.util.Map; -import java.util.logging.Logger; - -// This is the Pub/Sub message format from the Pub/Sub emulator. -class PubSubMessage { - String data; - Map attributes; - String messageId; - String publishTime; -} - -public class PubSubBackground implements BackgroundFunction { - private static final Logger logger = - Logger.getLogger(PubSubBackground.class.getName()); - - @Override - public void accept(PubSubMessage pubSubMessage, Context context) { - logger.info("Received message with id " + context.eventId()); - } -} -``` - - -## Running a function with the Maven plugin - -The Maven plugin called `function-maven-plugin` allows you to run functions -on your development machine. - -### Configuration in `pom.xml` - -You can configure the plugin in `pom.xml`: - -```xml - - com.google.cloud.functions - function-maven-plugin - 0.10.0 - - com.example.function.Echo - - -``` - -Then run it from the command line: - -```sh -mvn function:run -``` - -### Configuration on the command line - -You can alternatively configure the plugin with properties on the command line: - -```sh - mvn com.google.cloud.functions:function-maven-plugin:0.10.0:run \ - -Drun.functionTarget=com.example.function.Echo -``` - -### Running the Functions Framework directly - -You can also run a function by using the Functions Framework jar directly. -Copy the Functions Framework jar to a local location like this: - -```sh -mvn dependency:copy \ - -Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.1.0' \ - -DoutputDirectory=. -``` - -In this example we use the current directory `.` but you can specify any other -directory to copy to. Then run your function: - -```sh -java -jar java-function-invoker-1.1.0 \ - --classpath myfunction.jar \ - --target com.example.HelloWorld -``` - - -## Running a function with Gradle - -From Gradle, similarily to running functions with the Functions Framework jar, -we can invoke the `Invoker` class with a `JavaExec` task. - -### Configuration in `build.gradle` - -```groovy -configurations { - invoker -} - -dependencies { - implementation 'com.google.cloud.functions:functions-framework-api:1.0.4' - invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.1.0' -} - -tasks.register("runFunction", JavaExec) { - main = 'com.google.cloud.functions.invoker.runner.Invoker' - classpath(configurations.invoker) - inputs.files(configurations.runtimeClasspath, sourceSets.main.output) - args( - '--target', project.findProperty('run.functionTarget'), - '--port', project.findProperty('run.port') ?: 8080 - ) - doFirst { - args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath) - } -} -``` - -Then in your terminal or IDE, you will be able to run the function locally with: - -```sh -gradle runFunction -Prun.functionTarget=com.example.HelloWorld \ - -Prun.port=8080 -``` - -Or if you use the Gradle wrapper provided by your Gradle project build: - -```sh -./gradlew runFunction -Prun.functionTarget=com.example.HelloWorld \ - -Prun.port=8080 -``` - -## Functions Framework configuration - -There are a number of options that can be used to configure the Functions -Framework, whether run directly or on the command line. - -### Which function to run - -A function is a Java class. You must specify the name of that class when running -the Functions Framework: - -``` ---target com.example.HelloWorld -com.example.HelloWorld --Drun.functionTarget=com.example.HelloWorld --Prun.functionTarget=com.example.HelloWorld -``` - -* Invoker argument: `--target com.example.HelloWorld` -* Maven `pom.xml`: `com.example.HelloWorld` -* Maven CLI argument: `-Drun.functionTarget=com.example.HelloWorld` -* Gradle CLI argument: `-Prun.functionTarget=com.example.HelloWorld` - -### Which port to listen on - -The Functions Framework is an HTTP server that directs incoming HTTP requests to -the function code. By default this server listens on port 8080. Specify an -alternative value like this: - -* Invoker argument: `--port 12345` -* Maven `pom.xml`: `12345` -* Maven CLI argument: `-Drun.port=12345` -* Gradle CLI argument: `-Prun.port=12345` - -### Function classpath - -Function code runs with a classpath that includes the function code itself and -its dependencies. The Maven plugin automatically computes the classpath based -on the dependencies expressed in `pom.xml`. When invoking the Functions -Framework directly, you must use `--classpath` to indicate how to find the code -and its dependencies. For example: - -``` -java -jar java-function-invoker-1.1.0 \ - --classpath 'myfunction.jar:/some/directory:/some/library/*' \ - --target com.example.HelloWorld -``` - -The `--classpath` option works like -[`java -classpath`](https://docs.oracle.com/en/java/javase/13/docs/specs/man/java.html#standard-options-for-java). -It is a list of entries separated by `:` (`;` on Windows), where each entry is: - -* a directory, in which case class `com.example.Foo` is looked for in a file - `com/example/Foo.class` under that directory; -* a jar file, in which case class `com.example.Foo` is looked for in a file - `com/example/Foo.class` in that jar file; -* a directory followed by `/*` (`\*` on Windows), in which case each jar file - in that directory (file called `foo.jar`) is treated the same way as if it - had been named explicitly. - -#### Simplifying the claspath - -Specifying the right classpath can be tricky. A simpler alternative is to -build the function as a "fat jar", where the function code and all its -dependencies are in a single jar file. Then `--classpath myfatfunction.jar` -is enough. An example of how this is done is the Functions Framework jar itself, -as seen -[here](https://github.com/GoogleCloudPlatform/functions-framework-java/blob/b627f28/invoker/core/pom.xml#L153). - -Alternatively, you can arrange for your jar to have its own classpath, as -described -[here](https://maven.apache.org/shared/maven-archiver/examples/classpath.html). +An open source FaaS (Function as a service) framework for writing portable Java functions. diff --git a/functions-framework-api/pom.xml b/functions-framework-api/pom.xml index 7e6c52db..6d6f4495 100644 --- a/functions-framework-api/pom.xml +++ b/functions-framework-api/pom.xml @@ -116,6 +116,12 @@ sign + + + --pinentry-mode + loopback + + @@ -151,11 +157,11 @@ - sonatype-nexus-snapshots + ossrh https://s01.oss.sonatype.org/content/repositories/snapshots - sonatype-nexus-staging + ossrh https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ diff --git a/functions-framework-invoker/pom.xml b/functions-framework-invoker/pom.xml index 40cefec8..7efc88af 100644 --- a/functions-framework-invoker/pom.xml +++ b/functions-framework-invoker/pom.xml @@ -216,6 +216,12 @@ sign + + + --pinentry-mode + loopback + + @@ -253,11 +259,11 @@ - sonatype-nexus-snapshots + ossrh https://s01.oss.sonatype.org/content/repositories/snapshots - sonatype-nexus-staging + ossrh https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/