Skip to content

Commit 6f335b4

Browse files
Merge pull request #18 from PoshWeb/fun-server
Fun 0.1
2 parents 9d01e23 + 4159098 commit 6f335b4

22 files changed

Lines changed: 2100 additions & 0 deletions

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [StartAutomating]

.github/workflows/BuildFun.yml

Lines changed: 598 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/deploy.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Simple workflow for deploying static content to GitHub Pages
2+
name: deploy
3+
4+
on:
5+
# Runs on pushes
6+
push:
7+
branches:
8+
- 'main'
9+
# and run on a schedule
10+
schedule:
11+
# for those that don't speak cron, this runs:
12+
# * At the first minute (`1`)
13+
# * Every 21st hour (`1/21`)
14+
# * Every day of the year (`* * *`)
15+
- cron: '1 1/21 * * *'
16+
# Allows you to run this workflow manually from the Actions tab
17+
workflow_dispatch:
18+
19+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
20+
permissions:
21+
contents: read
22+
pages: write
23+
id-token: write
24+
25+
# Allow only one concurrent deployment, and cancel any in-progress deployments if a new one is triggered
26+
concurrency:
27+
group: "pages"
28+
cancel-in-progress: true
29+
30+
jobs:
31+
# GitHub Pages use a single job, named deploy.
32+
deploy:
33+
# By using an environment, we avoid locking
34+
environment:
35+
name: github-pages
36+
# and we can control where it is deployed.
37+
url: ${{ steps.deployment.outputs.page_url }}
38+
runs-on: ubuntu-latest
39+
steps:
40+
# Check out our repository
41+
- name: Checkout
42+
uses: actions/checkout@main
43+
with:
44+
# Using fetch-depth: 0 to ensure we get the full history of the repository
45+
fetch-depth: 0
46+
# Setup GitHub Pages
47+
- name: Setup Pages
48+
uses: actions/configure-pages@main
49+
# To Build Pages in PowerShell, we just call a script
50+
- name: Build Pages
51+
# set the shell to pwsh
52+
shell: pwsh
53+
# and then call any script we would like to build the page.
54+
# By default, this can use the same name as the workflow
55+
# (in this case, just deploy.ps1)
56+
run: . "./$env:GITHUB_WORKFLOW.ps1"
57+
# This approach makes it easier to logically organize workflow scripts.
58+
# We will also map the page_url to an environment variable, so our scripts can access it.
59+
env:
60+
site_url: ${{ steps.deployment.outputs.page_url }}
61+
page_url: ${{ steps.deployment.outputs.page_url }}
62+
analytics_id: ${{vars.ANALYTICSID}}
63+
- name: Upload artifact
64+
uses: actions/upload-pages-artifact@main
65+
with:
66+
# Upload the contents to the GitHub Pages artifact
67+
path: './'
68+
- name: Deploy to GitHub Pages
69+
id: deployment
70+
uses: actions/deploy-pages@main
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#requires -Module PSDevOps
2+
Import-BuildStep -SourcePath (
3+
Join-Path $PSScriptRoot 'GitHub'
4+
) -BuildSystem GitHubWorkflow
5+
6+
Push-Location ($PSScriptRoot | Split-Path)
7+
8+
New-GitHubWorkflow -Name "Build Fun" -On Push, PullRequest, Demand -Job PowerShellStaticAnalysis,
9+
TestPowerShellOnLinux,
10+
TagReleaseAndPublish,
11+
buildfun -OutputPath .\.github\workflows\BuildFun.yml
12+
13+
Pop-Location

Build/GitHub/Jobs/BuildFun.psd1

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
@{
2+
"runs-on" = "ubuntu-latest"
3+
if = '${{ success() }}'
4+
steps = @(
5+
@{
6+
name = 'Check out repository'
7+
uses = 'actions/checkout@main'
8+
}
9+
10+
@{
11+
'name'='Log in to the Container registry'
12+
if = '${{github.ref_name == ''main'' || github.ref_name == ''master'' || github.ref_name == ''latest''}}'
13+
'uses'='docker/login-action@master'
14+
'with'=@{
15+
'registry'='${{ env.REGISTRY }}'
16+
'username'='${{ github.actor }}'
17+
'password'='${{ secrets.GITHUB_TOKEN }}'
18+
}
19+
}
20+
@{
21+
name = 'Extract Docker Metadata (for main)'
22+
if = '${{github.ref_name == ''main'' || github.ref_name == ''master'' || github.ref_name == ''latest''}}'
23+
'id'='metaMain'
24+
'uses'='docker/metadata-action@master'
25+
'with'=@{
26+
'images'='${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}'
27+
'flavor'='latest=true'
28+
}
29+
}
30+
31+
@{
32+
name = 'Build and push Docker image (from main)'
33+
if = '${{github.ref_name == ''main'' || github.ref_name == ''master'' || github.ref_name == ''latest''}}'
34+
uses = 'docker/build-push-action@master'
35+
'with'=@{
36+
'context'='.'
37+
'push'='true'
38+
'tags'='${{ steps.metaMain.outputs.tags }}'
39+
'labels'='${{ steps.metaMain.outputs.labels }}'
40+
}
41+
}
42+
43+
<#,
44+
@{
45+
name = 'Use PSSVG Action'
46+
uses = 'StartAutomating/PSSVG@main'
47+
id = 'PSSVG'
48+
}
49+
@{
50+
name = 'Run ugit (from main)'
51+
if = '${{github.ref_name == ''main''}}'
52+
uses = 'StartAutomating/ugit@main'
53+
id = 'ugitMain'
54+
},
55+
@{
56+
name = 'Run ugit (on branch)'
57+
if = '${{github.ref_name != ''main''}}'
58+
uses = './'
59+
id = 'ugitBranch'
60+
}
61+
'RunPipeScript',
62+
'RunPiecemeal',
63+
'RunEZOut',
64+
@{
65+
name = 'Run HelpOut'
66+
uses = 'StartAutomating/HelpOut@master'
67+
id = 'HelpOut'
68+
},
69+
@{
70+
'name'='Log in to the Container registry (on branch)'
71+
'uses'='docker/login-action@master'
72+
'with'=@{
73+
'registry'='${{ env.REGISTRY }}'
74+
'username'='${{ github.actor }}'
75+
'password'='${{ secrets.GITHUB_TOKEN }}'
76+
}
77+
},
78+
@{
79+
name = 'Extract Docker Metadata (for branch)'
80+
if = '${{github.ref_name != ''main'' && github.ref_name != ''master'' && github.ref_name != ''latest''}}'
81+
'id'='meta'
82+
'uses'='docker/metadata-action@master'
83+
'with'=@{
84+
'images'='${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}'
85+
}
86+
},
87+
@{
88+
name = 'Extract Docker Metadata (for main)'
89+
if = '${{github.ref_name == ''main'' || github.ref_name == ''master'' || github.ref_name == ''latest''}}'
90+
'id'='metaMain'
91+
'uses'='docker/metadata-action@master'
92+
'with'=@{
93+
'images'='${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}'
94+
'flavor'='latest=true'
95+
}
96+
},
97+
@{
98+
name = 'Build and push Docker image (from main)'
99+
if = '${{github.ref_name == ''main'' || github.ref_name == ''master'' || github.ref_name == ''latest''}}'
100+
uses = 'docker/build-push-action@master'
101+
'with'=@{
102+
'context'='.'
103+
'push'='true'
104+
'tags'='${{ steps.metaMain.outputs.tags }}'
105+
'labels'='${{ steps.metaMain.outputs.labels }}'
106+
}
107+
},
108+
@{
109+
name = 'Build and push Docker image (from branch)'
110+
if = '${{github.ref_name != ''main'' && github.ref_name != ''master'' && github.ref_name != ''latest''}}'
111+
uses = 'docker/build-push-action@master'
112+
with = @{
113+
'context'='.'
114+
'push'='true'
115+
'tags'='${{ steps.meta.outputs.tags }}'
116+
'labels'='${{ steps.meta.outputs.labels }}'
117+
}
118+
} #>
119+
)
120+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@{
2+
name = 'PublishTestResults'
3+
uses = 'actions/upload-artifact@main'
4+
with = @{
5+
name = 'PesterResults'
6+
path = '**.TestResults.xml'
7+
}
8+
if = '${{always()}}'
9+
}
10+

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Fun Server 0.1
2+
3+
* `Fun` is a fun functional PowerShell server (#1)
4+
* `Fun.ps1` defines a fun server (#2)
5+
* `Fun.psm1` defines eponyoms for Fun.ps1 (#3)
6+
* `Fun` has a build workflow (#4)
7+
* `Fun` has tests (#6)
8+
* `Fun` GitHub common documents
9+
* `Fun` `security.md` (#5)
10+
* `Fun` `contributing.md` (#7)
11+
* `Fun` `code_of_conduct.md` (#8)
12+
* `Fun` can run in a container
13+
* Dockerfile (#9)
14+
* Container.init.ps1 (#10)
15+
* Container.start.ps1 (#11)
16+
* Container.stop.ps1 (#12)
17+
* Example Site:
18+
* `Fun.fun.ps1` (#13)
19+
* Sponsorship support (#14)
20+
* GitHub Page
21+
* `deploy.ps1` (#15)
22+
* `deploy.yml` (#16)
23+
* README.md.ps1 (#17)

Container.init.ps1

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<#
2+
.SYNOPSIS
3+
Initializes a container during build.
4+
.DESCRIPTION
5+
Initializes the container image with the necessary modules and packages.
6+
7+
The scripts arguments can be provided with either an `ARG` or `ENV` instruction in the Dockerfile.
8+
#>
9+
10+
param(
11+
# The name of the module to be installed.
12+
[string]$ModuleName = $(
13+
if ($env:ModuleName) { $env:ModuleName }
14+
else { 'Fun' }
15+
),
16+
# The modules to be installed.
17+
[string[]]$InstallModules = @(
18+
if ($env:InstallModules) { $env:InstallModules -split ',' }
19+
)
20+
)
21+
22+
# Get the root module directory
23+
$rootModuleDirectory = @($env:PSModulePath -split '[;:]')[0]
24+
25+
# Determine the path to the module destination.
26+
$moduleDestination = "$rootModuleDirectory/$ModuleName"
27+
# Copy the module to the destination
28+
# (this is being used instead of the COPY statement in Docker, to avoid additional layers).
29+
Copy-Item -Path "$psScriptRoot" -Destination $moduleDestination -Recurse -Force
30+
31+
# Copy all container-related scripts to the root of the container.
32+
Get-ChildItem -Path $PSScriptRoot |
33+
Where-Object Name -Match '^Container\..+?\.ps1$' |
34+
Copy-Item -Destination /
35+
36+
# Create a new profile
37+
New-Item -Path $Profile -ItemType File -Force |
38+
# and import this module in the profile
39+
Add-Content -Value "Import-Module $ModuleName" -Force
40+
# If we have modules to install
41+
if ($InstallModules) {
42+
# Install the modules
43+
Install-Module -Name $InstallModules -Force -AcceptLicense -Scope CurrentUser
44+
# and import them in the profile
45+
Add-Content -Path $Profile -Value "Import-Module '$($InstallModules -join "','")'" -Force
46+
}
47+
# In our profile, push into the module's directory
48+
Add-Content -Path $Profile -Value "Get-Module $ModuleName | Split-Path | Push-Location" -Force
49+
50+
# Remove the .git directories from any modules
51+
Get-ChildItem -Path $rootModuleDirectory -Directory -Force -Recurse |
52+
Where-Object Name -eq '.git' |
53+
Remove-Item -Recurse -Force
54+
55+
# Congratulations! You have successfully initialized the container image.
56+
# This script should work in about any module, with minor adjustments.
57+
# If you have any adjustments, please put them below here, in the `#region Custom`
58+
59+
#region Custom
60+
61+
#endregion Custom
62+

Container.start.ps1

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<#
2+
.SYNOPSIS
3+
Starts the container.
4+
.DESCRIPTION
5+
Starts a container.
6+
7+
This script should be called from the Dockerfile as the ENTRYPOINT (or from within the ENTRYPOINT).
8+
9+
It should be deployed to the root of the container image.
10+
#>
11+
12+
param()
13+
14+
$env:IN_CONTAINER = $true
15+
$PSStyle.OutputRendering = 'Ansi'
16+
17+
$mountedDrives = @(if (Test-Path '/proc/mounts') {
18+
(Select-String "\S+\s(?<p>\S+).+rw?,.+symlinkroot=/mnt/host" "/proc/mounts").Matches.Groups |
19+
Where-Object Name -eq p |
20+
Get-Item -path { $_.Value }
21+
})
22+
23+
if ($global:ContainerInfo.MountedPaths) {
24+
"Mounted $($mountedDrives.Length) drives:" | Out-Host
25+
$mountedDrives | Out-Host
26+
}
27+
28+
function / {
29+
30+
"Hello from Fun."
31+
32+
"It is $([DateTime]::Now.ToString())."
33+
34+
"Here's a random number $([Random]::new().next())."
35+
}
36+
37+
38+
39+
if ($args) {
40+
# If there are arguments, output them (you could handle them in a more complex way).
41+
$remainingArgs = @(foreach ($arg in $args) {
42+
if ($arg -match '\.ps1$' -and (Test-Path $arg)) {
43+
. $arg
44+
} else {
45+
$arg
46+
}
47+
})
48+
49+
$fun = fun "http://*/" @remainingArgs
50+
# Launch three replicas
51+
$fun.Start();$fun.Start();$fun.Start()
52+
} else {
53+
if (Test-Path ./Fun.fun.ps1) {
54+
. ./Fun.fun.ps1
55+
} else {
56+
function / { "Hello from Fun" }
57+
}
58+
$fun = fun "http://*/"
59+
# Launch three replicas
60+
$fun.Start();$fun.Start();$fun.Start()
61+
}
62+
63+
64+
# If you want to do something when the container is stopped, you can register an event.
65+
# This can call a script that does some cleanup, or sends a message as the service is exiting.
66+
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
67+
Get-Job |
68+
Where-Object HttpListener |
69+
ForEach-Object {
70+
$_.HttpListener.Stop()
71+
}
72+
if (Test-Path '/Container.stop.ps1') {
73+
& /Container.stop.ps1
74+
}
75+
} | Out-Null

0 commit comments

Comments
 (0)